<template>
	<div class="network-graph-container" ref="containerRef">
		<svg ref="svgRef" class="network-svg" @contextmenu.prevent @click="handleCanvasClick">
			<defs>
				<!-- 箭头 -->
				<marker
					id="arrowhead"
					markerWidth="10"
					markerHeight="7"
					refX="8"
					refY="3.5"
					orient="auto"
					markerUnits="strokeWidth"
				>
					<path d="M0,0 L0,7 L8,3.5 z" fill="#999" />
				</marker>

				<marker
					id="arrowhead-highlight"
					markerWidth="10"
					markerHeight="7"
					refX="8"
					refY="3.5"
					orient="auto"
					markerUnits="strokeWidth"
				>
					<path d="M0,0 L0,7 L8,3.5 z" fill="#4a90e2" />
				</marker>

				<!-- 阴影滤镜 -->
				<filter id="drop-shadow" x="-50%" y="-50%" width="200%" height="200%">
					<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
					<feOffset dx="0" dy="2" result="offset" />
					<feComponentTransfer>
						<feFuncA type="linear" slope="0.3" />
					</feComponentTransfer>
					<feMerge>
						<feMergeNode />
						<feMergeNode in="SourceGraphic" />
					</feMerge>
				</filter>
			</defs>

			<g class="zoom-group">
				<g class="links-group"></g>
				<g class="nodes-group"></g>
				<g class="labels-group"></g>
			</g>
		</svg>

		<!-- 右键菜单 -->
		<div
			v-show="contextMenu.visible && isEdit"
			class="context-menu"
			:style="{
				left: contextMenu.x + 'px',
				top: contextMenu.y + 'px'
			}"
			@click.stop
		>
			<div class="menu-item" @click="handleAddNode">
				<i class="icon-add"></i>
				<span>添加节点</span>
			</div>
			<div class="menu-item" @click="handleEditNode">
				<i class="icon-edit"></i>
				<span>编辑当前节点</span>
			</div>
			<div class="menu-separator"></div>
			<div class="menu-item danger" @click="handleDeleteNode">
				<i class="icon-delete"></i>
				<span>删除当前节点</span>
			</div>
		</div>

		<!-- 节点信息气泡框 -->
		<div ref="nodeTooltipRef" class="node-tooltip" v-show="tooltipVisible" :style="tooltipStyle">
			<div class="tooltip-content">
				<div class="tooltip-title">{{ tooltipData.name }}</div>
				<div class="tooltip-type">类型：{{ tooltipData.type }}</div>
			</div>
			<div class="tooltip-arrow"></div>
		</div>

		<!-- 节点编辑抽屉 -->
		<el-drawer
			v-model="nodeEditDialog.visible"
			:title="nodeEditDialog.isAdd ? '添加节点' : '编辑节点'"
			direction="rtl"
			size="600px"
			:before-close="handleDrawerClose"
			destroy-on-close
		>
			<div class="drawer-content">
				<div class="drawer-body">
					<!-- 节点基本信息 -->
					<div class="form-section">
						<h4>节点信息</h4>
						<div class="form-row">
							<div class="form-group">
								<label>节点名称 *</label>
								<el-input
									v-model="nodeEditDialog.form.nodeName"
									placeholder="请输入节点名称"
									maxlength="50"
									show-word-limit
									clearable
								/>
							</div>
							<div class="form-group">
								<label>节点类型 *</label>
								<el-select
									v-model="nodeEditDialog.form.nodeType"
									placeholder="请选择节点类型"
									filterable
									clearable
									style="width: 100%"
								>
									<el-option
										v-for="(nodeType, index) in nodeStyleByType"
										:key="index"
										:value="nodeType.type || nodeType.name"
										:label="nodeType.type || nodeType.name"
									/>
								</el-select>
							</div>
						</div>
					</div>

					<!-- 节点关系 -->
					<div class="form-section">
						<div class="section-header">
							<h4>节点关系</h4>
							<button class="btn-add" @click="addRelation">
								<i class="icon-add"></i>
								添加关系
							</button>
						</div>

						<div v-if="nodeEditDialog.form.relations.length === 0" class="empty-state">
							暂无关系，点击上方"添加关系"按钮来添加
						</div>

						<div
							v-for="(relation, index) in nodeEditDialog.form.relations.slice().reverse()"
							:key="nodeEditDialog.form.relations.length - 1 - index"
							class="relation-item"
						>
							<div class="relation-header">
								<span class="relation-index"
									># {{ nodeEditDialog.form.relations.length - index }}</span
								>
								<button
									class="btn-remove"
									@click="removeRelation(nodeEditDialog.form.relations.length - 1 - index)"
								>
									<i class="icon-delete"></i>
									删除
								</button>
							</div>

							<div class="relation-form">
								<div class="form-row">
									<div class="form-group">
										<label>关系类型</label>
										<el-select
											v-model="relation.label"
											placeholder="请选择关系类型"
											filterable
											clearable
											style="width: 100%"
										>
											<el-option
												v-for="(relationType, index) in relationStyleByType"
												:key="index"
												:value="relationType.label || relationType.name"
												:label="relationType.label || relationType.name"
											/>
										</el-select>
									</div>
								</div>

								<div class="form-row direction-row">
									<div class="form-group">
										<label>源节点</label>
										<div
											v-if="isCurrentNodeInPosition(relation, 'source')"
											class="current-node-display"
										>
											<span class="current-node-text">{{ currentNodeLabel }}</span>
											<span class="current-node-badge">当前节点</span>
										</div>
										<el-select
											v-else
											v-model="relation.sourceNodeId"
											placeholder="请选择源节点"
											filterable
											clearable
											style="width: 100%"
										>
											<el-option
												v-for="node in availableNodes"
												:key="node.id"
												:value="node.id"
												:label="node.label"
												:disabled="node.id === relation.targetNodeId"
											/>
										</el-select>
									</div>

									<div class="direction-switch">
										<button
											class="btn-switch"
											@click="switchRelationDirection(index)"
											title="交换源节点和目标节点"
										>
											⇄
										</button>
									</div>

									<div class="form-group">
										<label>目标节点</label>
										<div
											v-if="isCurrentNodeInPosition(relation, 'target')"
											class="current-node-display"
										>
											<span class="current-node-text">{{ currentNodeLabel }}</span>
											<span class="current-node-badge">当前节点</span>
										</div>
										<el-select
											v-else
											v-model="relation.targetNodeId"
											placeholder="请选择目标节点"
											filterable
											clearable
											style="width: 100%"
										>
											<el-option
												v-for="node in availableNodes"
												:key="node.id"
												:value="node.id"
												:label="node.label"
												:disabled="node.id === relation.sourceNodeId"
											/>
										</el-select>
									</div>
								</div>
							</div>
						</div>
					</div>
				</div>

				<!-- 抽屉底部按钮 -->
				<div class="drawer-footer">
					<el-button @click="handleDrawerClose">取消</el-button>
					<el-button type="primary" @click="handleDrawerConfirm">
						{{ nodeEditDialog.isAdd ? '添加' : '保存' }}
					</el-button>
				</div>
			</div>
		</el-drawer>

		<!-- 关系编辑抽屉 -->
		<el-drawer
			v-model="relationEditDialog.visible"
			title="编辑关系"
			direction="rtl"
			size="500px"
			:before-close="handleRelationDrawerClose"
			destroy-on-close
		>
			<div class="drawer-content">
				<div class="drawer-body">
					<!-- 关系基本信息 -->
					<div class="form-section">
						<h4>关系信息</h4>
						<div class="form-row">
							<div class="form-group">
								<label>关系类型</label>
								<el-select
									v-model="relationEditDialog.form.relationLabel"
									placeholder="请选择关系类型"
									filterable
									clearable
									style="width: 100%"
								>
									<el-option
										v-for="(relationType, index) in relationStyleByType"
										:key="index"
										:value="relationType.label || relationType.name"
										:label="relationType.label || relationType.name"
									/>
								</el-select>
							</div>
						</div>
					</div>

					<!-- 节点关系方向 -->
					<div class="form-section">
						<h4>关系方向</h4>
						<div class="relation-direction-container">
							<div class="direction-row">
								<div class="node-info source-node">
									<div class="node-label">源节点</div>
									<div class="node-display">
										<span class="node-name">{{ sourceNodeName }}</span>
										<span class="node-type">({{ sourceNodeType }})</span>
									</div>
								</div>

								<div class="direction-arrow">
									<button
										class="btn-switch-direction"
										@click="switchRelationNodes"
										title="交换源节点和目标节点"
									>
										⇄
									</button>
								</div>

								<div class="node-info target-node">
									<div class="node-label">目标节点</div>
									<div class="node-display">
										<span class="node-name">{{ targetNodeName }}</span>
										<span class="node-type">({{ targetNodeType }})</span>
									</div>
								</div>
							</div>
						</div>
					</div>
				</div>

				<!-- 抽屉底部按钮 -->
				<div class="drawer-footer">
					<el-button @click="handleRelationDrawerClose">取消</el-button>
					<el-button type="primary" @click="handleRelationDrawerConfirm"> 保存 </el-button>
				</div>
			</div>
		</el-drawer>
	</div>
</template>

<script setup lang="ts">
import * as d3 from 'd3';
import { ref, watch, computed, onMounted, onBeforeUnmount, nextTick } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import {
	NodeItemType,
	LinkItemType,
	RelationStyleByType,
	RelationStyleByTypeItem,
	NodeStyleByType,
	NodeStyleByTypeItem,
	SimulationNodeType,
	SimulationLinkType,
	NetworkNodeElType,
	ContextMenuType,
	NodeEditDialogType,
	NodeUpdateType,
	ValidUpdatedRelationItemType,
	AddRelationItemType,
	AddRelationResultType,
	RelationEditedType
} from './NetworkGraph.type';

const props = withDefaults(
	defineProps<{
		// 初始化数据
		initialData: { nodes: NodeItemType[]; links: LinkItemType[] };
		// 默认节点样式
		defaultNodeStyle?: { color: string; size: number };
		// 布局配置
		layoutConfig?: {
			linkDistance: number;
			chargeStrength: number; // 吸引力
			friction: number; // 摩擦力
			centeringStrength: number; // 中心力
			collisionRadius: number; // 碰撞半径
		};
		// 连线样式配置
		linkStyle?: {
			type: 'curve' | 'straight';
			curvature: number; // 曲线弯曲程度 (0-1)
		};
		// 关系类型列表
		relationStyleByType: RelationStyleByType;
		// 节点类型列表
		nodeStyleByType?: NodeStyleByType;
		// 高亮时节点群中心在画布的位置（x、y百分比），默认 [0.5, 0.5] 表示画布中心
		centerPosition?: [number, number] | undefined;
		// 不采用 centerPosition 的节点 ID 列表，当点击这些节点时，使用默认中心位置（50%, 50%）、不进行搜索的节点类型列表
		excludeNodeList?: string[];
		// 是否编辑
		isEdit?: boolean;
		// 默认展开的层级，数字表示展开到第几层，'all' 表示全部展开
		defaultExpandLevel?: number | 'all';
		// 节点类型映射（用于气泡框显示中文）
		typeMap?: Map<string, string>;
		// 缩放初始值（百分比，20-400，默认100，对应 d3 scale 0.2-4）
		zoomValue?: number;
	}>(),
	{
		initialData: () => ({ nodes: [], links: [] }),
		defaultNodeStyle: () => ({ color: '#4E84E4', size: 30 }),
		layoutConfig: () => ({
			linkDistance: 200,
			chargeStrength: -200,
			friction: 0.9,
			centeringStrength: 0.1,
			collisionRadius: 15
		}),
		linkStyle: () => ({ type: 'curve', curvature: 0.1 }),
		relationStyleByType: () => [],
		nodeStyleByType: () => [],
		centerPosition: () => [0.5, 0.5],
		excludeNodeList: () => [],
		isEdit: false,
		defaultExpandLevel: undefined,
		typeMap: () => new Map(),
		zoomValue: 100
	}
);

// d3实例
const svg = ref<d3.Selection<SVGSVGElement, unknown, null, undefined> | null>(null);
const zoomGroup = ref<d3.Selection<SVGGElement, unknown, SVGSVGElement, unknown> | null>(null);
const simulation = ref<d3.Simulation<NodeItemType & d3.SimulationNodeDatum, LinkItemType> | null>(
	null
);
const zoom = ref<d3.ZoomBehavior<SVGSVGElement, unknown> | null>(null);

watch(
	() => props.initialData,
	(newVal) => {
		if (newVal) {
			// 处理初始化数据
			processInitialData();
		}
	},
	{ deep: true }
);

watch(
	() => props.nodeStyleByType,
	(newVal, oldVal) => {
		// 监听linkStyle变化，重新渲染连线
		if (simulation.value && newVal !== oldVal) {
			renderLinks();
		}
	},
	{ deep: true }
);

const emit = defineEmits<{
	(e: 'node-click', node: NetworkNodeElType): void;
	(e: 'node-added', data: { node: NodeItemType; relationList: LinkItemType[] }): void;
	(
		e: 'node-edited',
		data: { nodeId: string; node: NodeUpdateType; relationList: LinkItemType[] }
	): void;
	(e: 'delete-node', node: SimulationNodeType): void;
	(e: 'relation-edited', data: RelationEditedType): void;
	(e: 'update:zoomValue', value: number): void;
}>();

// 节点样式类型映射
const nodeTypeMap = computed<Map<string, NodeStyleByTypeItem>>(() => {
	const nodeTypeMap = new Map<string, NodeStyleByTypeItem>();
	props.nodeStyleByType.forEach((nodeType) => {
		if (nodeType.type || nodeType.name) {
			nodeTypeMap.set(nodeType.type || nodeType.name || '', nodeType);
		}
	});
	return nodeTypeMap;
});

// 关系样式类型映射
const relationTypeMap = computed<Map<string, RelationStyleByTypeItem>>(() => {
	const relationTypeMap = new Map<string, RelationStyleByTypeItem>();
	props.relationStyleByType.forEach((relationType) => {
		if (relationType.label || relationType.name) {
			relationTypeMap.set(relationType.label || relationType.name || '', relationType);
		}
	});
	return relationTypeMap;
});

onMounted(() => {
	// 初始化图形
	initializeGraph();
	// 初始化数据
	processInitialData();
	// 设置事件监听
	setupEventListeners();
});

onBeforeUnmount(() => {
	if (simulation.value) {
		simulation.value.stop();
	}
	clearHoverTimer();
	clearTickTimer();
	removeEventListeners();
	// 清理 tooltip 定时器
	if (tooltipHideTimer) {
		clearTimeout(tooltipHideTimer);
		tooltipHideTimer = null;
	}
	// 隐藏 tooltip
	tooltipVisible.value = false;
});

/** -------------------缩放功能------------------- */
// 内部缩放值（百分比）
const internalZoomValue = ref(props.zoomValue || 100);
// 标记是否正在通过程序设置缩放（避免循环更新）
const isApplyingZoom = ref(false);

// 将百分比转换为 d3 scale
// zoomValue: 20-400 (百分比，对应 scale 0.2-4)
// scale: 0.2-4 (d3 zoom scale)
const zoomValueToScale = (zoomValue: number): number => {
	// 线性映射：20% -> 0.2, 100% -> 1.0, 400% -> 4.0
	// 限制在 scaleExtent [0.2, 4] 范围内
	const scale = zoomValue / 100;
	return Math.max(0.2, Math.min(4, scale));
};

// 将 d3 scale 转换为百分比
const scaleToZoomValue = (scale: number): number => {
	// scale -> zoomValue (百分比)
	// scale 0.2-4 对应 zoomValue 20-400
	const zoomValue = scale * 100;
	return Math.max(20, Math.min(400, Math.round(zoomValue)));
};

// 根据 zoomValue 应用缩放
const applyZoomFromValue = (zoomValue: number) => {
	if (!zoom.value || !svg.value) return;

	// 中断之前的动画，避免动画冲突
	svg.value.interrupt();

	isApplyingZoom.value = true;
	const targetScale = zoomValueToScale(zoomValue);
	const currentTransform = d3.zoomTransform(svg.value.node() as SVGSVGElement);

	// 保持当前位置，只改变缩放比例
	const newTransform = d3.zoomIdentity
		.translate(currentTransform.x, currentTransform.y)
		.scale(targetScale);

	// 应用变换（带动画）
	const transition = svg.value
		.transition()
		.duration(300)
		.on('end', () => {
			// 动画真正完成时才重置标记，避免状态不同步
			isApplyingZoom.value = false;
		}) as d3.Transition<SVGSVGElement, unknown, null, undefined>;

	zoom.value.transform(transition, newTransform);
};

// 容器ref
const containerRef = ref<HTMLDivElement | null>(null);
// 图形ref
const svgRef = ref<SVGSVGElement | null>(null);
// 图形宽度
const width = ref<number>(0);
// 图形高度
const height = ref<number>(0);

/** -------------------性能优化相关------------------- */
// 有效连线列表
const validLinks = ref<LinkItemType[]>([]);
// 节点邻居表
const nodeNeighbors = ref<Map<string, Set<string>>>(new Map());
// 节点映射表
const nodeMap = ref<Map<string, NodeItemType>>(new Map());
// 帧定时器
const tickTimer = ref<ReturnType<typeof requestAnimationFrame> | null>(null);
// 视窗边界缓存
const lastViewBox = ref<{ x: number; y: number; width: number; height: number } | null>(null);

// 数据
const nodes = ref<NodeItemType[]>([]);
const links = ref<LinkItemType[]>([]);

// 节点展开/收起状态管理
const nodeExpandState = ref<Map<string, boolean>>(new Map()); // 节点ID -> 是否展开
const nodeChildrenMap = ref<Map<string, Set<string>>>(new Map()); // 节点ID -> 子节点ID集合
const nodeParentMap = ref<Map<string, string>>(new Map()); // 子节点ID -> 父节点ID
const nodeLevelMap = ref<Map<string, number>>(new Map()); // 节点ID -> 层级（从0开始）

/** -------------------初始化图形------------------- */
const initializeGraph = () => {
	const containerRect = containerRef.value?.getBoundingClientRect();
	if (containerRect) {
		width.value = containerRect.width;
		height.value = containerRect.height;
	}

	if (!svgRef.value) return;

	svg.value = d3.select(svgRef.value).attr('width', width.value).attr('height', height.value);

	zoomGroup.value = svg.value.select('.zoom-group') as unknown as d3.Selection<
		SVGGElement,
		unknown,
		SVGSVGElement,
		unknown
	>;

	// 初始化缩放行为
	zoom.value = d3.zoom<SVGSVGElement, unknown>().scaleExtent([0.2, 4]).on('zoom', handleZoom);
	if (zoom.value && svg.value) {
		svg.value.call(zoom.value);
		// 应用初始缩放值
		nextTick(() => {
			if (props.zoomValue !== undefined) {
				applyZoomFromValue(props.zoomValue);
			}
		});
	}

	// 初始化视窗边界缓存
	lastViewBox.value = calculateViewBox();

	// 初始化力模拟
	initializeSimulation();
};

// 缩放处理 - 添加视窗更新和同步到 zoomValue
const handleZoom = (event: d3.D3ZoomEvent<SVGSVGElement, unknown>) => {
	if (zoomGroup.value) {
		zoomGroup.value.attr('transform', event.transform.toString());
	}

	// 同步缩放值到 zoomValue（如果不是正在通过程序设置缩放）
	if (!isApplyingZoom.value) {
		const currentScale = event.transform.k;
		const newZoomValue = scaleToZoomValue(currentScale);

		// 避免循环更新，只有当变化超过 0.1% 时才更新
		if (Math.abs(newZoomValue - internalZoomValue.value) > 0.1) {
			internalZoomValue.value = newZoomValue;
			emit('update:zoomValue', newZoomValue);
		}
	}

	// 更新视窗边界缓存（仅在大数据量时使用）
	if (nodes.value.length > 500) {
		lastViewBox.value = calculateViewBox();
		// 可以在这里触发视窗裁剪更新，但为了保持功能不变，暂时不实现
	}
};

// 初始化力模拟 - 性能优化版本
const initializeSimulation = () => {
	const nodeCount = nodes.value.length;

	// 基于节点数量动态调整参数
	const scaleFactor = Math.min(1, 1000 / nodeCount);
	const isLargeDataset = nodeCount > 500;

	simulation.value = d3
		.forceSimulation<SimulationNodeType, LinkItemType>()
		.force(
			'link',
			d3
				.forceLink<SimulationNodeType, LinkItemType>()
				.id((d: SimulationNodeType) => d.id)
				.distance(props.layoutConfig.linkDistance)
				.iterations(Math.max(1, Math.floor(3 * scaleFactor))) // 减少迭代次数
		)
		.force(
			'charge',
			d3
				.forceManyBody<SimulationNodeType>()
				.strength(props.layoutConfig.chargeStrength * scaleFactor)
				.theta(isLargeDataset ? 1.2 : 0.9) // Barnes-Hut算法优化
		)
		.force(
			'center',
			d3
				.forceCenter(width.value / 2, height.value / 2)
				.strength(props.layoutConfig.centeringStrength)
		)
		.force(
			'collision',
			d3
				.forceCollide<SimulationNodeType>()
				.radius(
					(d: SimulationNodeType) =>
						(d.size || props.defaultNodeStyle.size) / 2 + props.layoutConfig.collisionRadius
				)
				.iterations(isLargeDataset ? 1 : 2) // 大数据量时减少碰撞检测
		)
		.velocityDecay(1 - props.layoutConfig.friction)
		.alpha(isLargeDataset ? 0.1 : 0.3) // 大数据量时降低初始动画强度
		.alphaDecay(isLargeDataset ? 0.05 : 0.0228) // 加快收敛
		.on('tick', handleTickOptimized);
};

// Tick 处理 - 优化版本，使用requestAnimationFrame节流
const handleTickOptimized = () => {
	// 使用 requestAnimationFrame 节流，避免过度更新
	if (tickTimer.value) return;

	tickTimer.value = requestAnimationFrame(() => {
		if (!zoomGroup.value) return;

		if (props.linkStyle.type === 'curve') {
			// 更新曲线连接位置
			(
				zoomGroup.value.selectAll('.link') as d3.Selection<
					SVGPathElement,
					SimulationLinkType,
					SVGGElement,
					unknown
				>
			).attr('d', (d) => {
				return generateCurvePath(d);
			});
		} else {
			// 更新直线连接位置 - 计算节点边缘位置
			const linkSelection = zoomGroup.value.selectAll('.link') as d3.Selection<
				SVGLineElement,
				SimulationLinkType,
				SVGGElement,
				unknown
			>;
			linkSelection.attr('x1', (d) => {
				const sourceRadius = (d.source.size || props.defaultNodeStyle.size) / 2;
				return getEdgePosition(d.source, d.target, sourceRadius).x;
			});
			linkSelection.attr('y1', (d) => {
				const sourceRadius = (d.source.size || props.defaultNodeStyle.size) / 2;
				return getEdgePosition(d.source, d.target, sourceRadius).y;
			});
			linkSelection.attr('x2', (d) => {
				const targetRadius = (d.target.size || props.defaultNodeStyle.size) / 2;
				return getEdgePosition(d.target, d.source, targetRadius).x;
			});
			linkSelection.attr('y2', (d) => {
				const targetRadius = (d.target.size || props.defaultNodeStyle.size) / 2;
				return getEdgePosition(d.target, d.source, targetRadius).y;
			});
		}

		// 更新连接标签位置
		const linkLabelSelection = zoomGroup.value.selectAll('.link-label') as d3.Selection<
			SVGTextElement,
			SimulationLinkType,
			SVGGElement,
			unknown
		>;
		linkLabelSelection.attr('x', (d) => {
			return getLinkLabelPosition(d).x;
		});
		linkLabelSelection.attr('y', (d) => {
			return getLinkLabelPosition(d).y;
		});

		// 更新节点位置
		const nodeSelection = zoomGroup.value.selectAll('.node-group') as d3.Selection<
			SVGGElement,
			SimulationNodeType,
			SVGGElement,
			unknown
		>;
		nodeSelection.attr('transform', (d) => `translate(${d.x ?? 0}, ${d.y ?? 0})`);

		// 更新标签组位置
		const labelSelection = zoomGroup.value.selectAll('.node-label-group') as d3.Selection<
			SVGGElement,
			SimulationNodeType,
			SVGGElement,
			unknown
		>;
		labelSelection.attr('transform', (d) => `translate(${d.x ?? 0}, ${d.y ?? 0})`);

		tickTimer.value = null;
	});
};

// 生成曲线路径
const generateCurvePath = (linkData: SimulationLinkType) => {
	const sourceRadius = (linkData.source.size || props.defaultNodeStyle.size) / 2;
	const targetRadius = (linkData.target.size || props.defaultNodeStyle.size) / 2;

	// 计算起点和终点在节点边缘的位置
	const sourceEdge = getEdgePosition(linkData.source, linkData.target, sourceRadius);
	const targetEdge = getEdgePosition(linkData.target, linkData.source, targetRadius);

	// 计算中点
	const midX = (sourceEdge.x + targetEdge.x) / 2;
	const midY = (sourceEdge.y + targetEdge.y) / 2;

	// 计算控制点 - 在中点的垂直方向上偏移
	const dx = targetEdge.x - sourceEdge.x;
	const dy = targetEdge.y - sourceEdge.y;
	const distance = Math.sqrt(dx * dx + dy * dy);

	// 避免除零错误
	if (distance === 0) {
		return `M ${sourceEdge.x},${sourceEdge.y} L ${targetEdge.x},${targetEdge.y}`;
	}

	// 计算垂直于连线的向量
	const perpX = -dy / distance;
	const perpY = dx / distance;

	// 根据curvature参数计算控制点偏移距离
	const offset = distance * props.linkStyle.curvature;
	const controlX = midX + perpX * offset;
	const controlY = midY + perpY * offset;

	// 生成二次贝塞尔曲线路径
	return `M ${sourceEdge.x},${sourceEdge.y} Q ${controlX},${controlY} ${targetEdge.x},${targetEdge.y}`;
};

/** -------------------处理数据------------------- */
// 处理初始化数据 - 添加数据预处理和缓存
const processInitialData = () => {
	// 深拷贝并处理节点数据
	nodes.value = JSON.parse(JSON.stringify(props.initialData.nodes)).map((node: NodeItemType) => {
		const nodeTypeConfig = nodeTypeMap.value?.get(node.type);
		return {
			...node,
			color: node.color || nodeTypeConfig?.color || props.defaultNodeStyle?.color,
			size: node.size || nodeTypeConfig?.size || props.defaultNodeStyle?.size,
			backgroundImg:
				resolveImagePath(node.backgroundImg || nodeTypeConfig?.backgroundImg || '') || '',
			// 渐变配置
			gradientStops: node.gradientStops || nodeTypeConfig?.gradientStops,
			gradientType: node.gradientType || nodeTypeConfig?.gradientType || 'linear', // 'linear' 或 'radial'
			gradientDir: node.gradientDir || nodeTypeConfig?.gradientDir || [0, 0, 0, 1], // 默认垂直渐变
			// D3 内部使用的属性
			x: Math.random() * width.value,
			y: Math.random() * height.value,
			vx: 0,
			vy: 0,
			// 图片加载状态
			_imageLoaded: false,
			_imageLoadFailed: false
		};
	});

	// 深拷贝连接数据
	links.value = JSON.parse(JSON.stringify(props.initialData.links));

	// 构建全局nodeMap缓存
	buildNodeMap();

	// 构建父子关系映射（用于展开/收起功能）
	buildNodeChildrenMap();

	// 预处理和缓存有效连线
	preprocessLinkData();

	// 更新模拟和渲染
	updateSimulation();
	renderGraph();
};

// 解析图片路径，处理 @/ 别名
const resolveImagePath = (path: string) => {
	if (!path) return null;

	// 处理 @/ 开头的路径，转换为相对于 public 目录的路径
	if (path.startsWith('@/assets/')) {
		// @/assets/images/xxx.png -> /src/assets/images/xxx.png
		// 注意：这需要图片文件存在于 public 目录或通过 vite 处理
		// 最佳实践：将图片放在 public 目录，然后使用 /images/xxx.png 这样的路径
		console.warn(
			`检测到 @/ 别名路径: ${path}。` +
				`建议使用绝对 URL 或将图片放在 public 目录并使用 /images/xxx.png 格式的路径。`
		);
		// 尝试转换为 public 路径（假设 assets 在 public 中有对应目录）
		return path.replace('@/assets/', '/assets/');
	}

	// 处理相对路径（如 ./images/xxx.png 或 ../images/xxx.png）
	if (path.startsWith('./') || path.startsWith('../')) {
		console.warn(
			`检测到相对路径: ${path}。` +
				`建议使用绝对 URL 或将图片放在 public 目录并使用 /images/xxx.png 格式的路径。`
		);
	}

	return path;
};

// 构建全局nodeMap缓存
const buildNodeMap = () => {
	nodeMap.value.clear();
	nodes.value.forEach((node) => {
		nodeMap.value.set(node.id, node);
	});
	console.log(`构建 nodeMap 完成，包含 ${nodeMap.value.size} 个节点`);
};

// 构建父子关系映射（用于展开/收起功能）
const buildNodeChildrenMap = () => {
	nodeChildrenMap.value.clear();
	nodeParentMap.value.clear();
	nodeLevelMap.value.clear();
	nodeExpandState.value.clear();

	// 遍历所有层级关系的连接，构建父子关系
	links.value.forEach((link) => {
		if (link.isHierarchy) {
			const sourceId =
				typeof link.source === 'string' ? link.source : (link.source as SimulationNodeType).id;
			const targetId =
				typeof link.target === 'string' ? link.target : (link.target as SimulationNodeType).id;

			if (!nodeChildrenMap.value.has(sourceId)) {
				nodeChildrenMap.value.set(sourceId, new Set());
			}
			nodeChildrenMap.value.get(sourceId)!.add(targetId);

			// 构建父节点映射
			nodeParentMap.value.set(targetId, sourceId);
		}
	});

	// 递归计算节点层级
	const calculateLevel = (nodeId: string, visited = new Set<string>()): number => {
		if (visited.has(nodeId)) {
			// 循环引用，返回已计算的层级或0
			return nodeLevelMap.value.get(nodeId) || 0;
		}

		if (nodeLevelMap.value.has(nodeId)) {
			return nodeLevelMap.value.get(nodeId)!;
		}

		visited.add(nodeId);
		const parentId = nodeParentMap.value.get(nodeId);

		if (!parentId) {
			// 根节点，层级为0
			nodeLevelMap.value.set(nodeId, 0);
			return 0;
		}

		// 父节点的层级 + 1
		const parentLevel = calculateLevel(parentId, visited);
		const level = parentLevel + 1;
		nodeLevelMap.value.set(nodeId, level);
		return level;
	};

	// 为所有节点计算层级
	nodes.value.forEach((node) => {
		if (!nodeLevelMap.value.has(node.id)) {
			calculateLevel(node.id);
		}
	});

	// 计算节点层级并设置展开状态
	// 根据 defaultExpandLevel 设置展开状态
	if (props.defaultExpandLevel === 'all') {
		// 全部展开
		nodeChildrenMap.value.forEach((_, nodeId) => {
			nodeExpandState.value.set(nodeId, true);
		});
	} else if (typeof props.defaultExpandLevel === 'number') {
		// 数字表示展开到第几层（level 从 0 开始，根节点是第 0 层）
		// 如果当前层级小于目标层级，则展开
		const targetLevel = props.defaultExpandLevel;
		nodeChildrenMap.value.forEach((_, nodeId) => {
			const level = nodeLevelMap.value.get(nodeId) || 0;
			const shouldExpand = level < targetLevel;
			nodeExpandState.value.set(nodeId, shouldExpand);
		});
	} else {
		// 默认所有节点都是展开状态
		nodeChildrenMap.value.forEach((_, nodeId) => {
			nodeExpandState.value.set(nodeId, true);
		});
	}
};

// 预处理连线数据和创建邻居缓存
const preprocessLinkData = () => {
	// 预处理并缓存有效连线
	validLinks.value = links.value.filter((link) => {
		const sourceId = (link.source as unknown as SimulationNodeType).id || link.source;
		const targetId = (link.target as unknown as SimulationNodeType).id || link.target;

		if (!sourceId || !targetId) {
			return false;
		}

		// 确保节点存在
		const sourceExists = getNodeById(sourceId);
		const targetExists = getNodeById(targetId);

		return sourceExists && targetExists;
	});

	// 预计算节点邻居表
	nodeNeighbors.value = new Map();
	validLinks.value.forEach((link) => {
		const sourceId = (link.source as unknown as SimulationNodeType).id || link.source;
		const targetId = (link.target as unknown as SimulationNodeType).id || link.target;

		if (!nodeNeighbors.value.has(sourceId)) {
			nodeNeighbors.value.set(sourceId, new Set());
		}
		if (!nodeNeighbors.value.has(targetId)) {
			nodeNeighbors.value.set(targetId, new Set());
		}

		nodeNeighbors.value?.get(sourceId)?.add(targetId);
		nodeNeighbors.value?.get(targetId)?.add(sourceId);
	});
};

// 更新力模拟 - 使用预处理的数据
const updateSimulation = () => {
	if (!simulation.value) return;

	// 使用预处理的有效连线，避免重复验证
	const linkForce = simulation.value.nodes(nodes.value).force('link') as d3.ForceLink<
		SimulationNodeType,
		LinkItemType
	> | null;
	if (linkForce) {
		linkForce.links(validLinks.value);
	}

	// 重启模拟
	simulation.value.alpha(0.1).restart();
};

// 渲染图形
const renderGraph = () => {
	renderLinks();
	renderNodes();
	renderLabels();
	// 在最后再调用一次，确保标签可见性正确
	updateNodeVisibility();
};

/** -------------------创建连接线------------------- */
// 渲染连接线 - 使用预处理的数据，支持视窗裁剪
const renderLinks = () => {
	const linksGroup = zoomGroup.value?.select('.links-group');
	if (!linksGroup) return;

	// 使用视窗裁剪优化（在大数据量时）
	const validLinks = getVisibleLinks();

	// 完全清除所有连接相关元素，避免样式切换时的冲突
	linksGroup.selectAll('*').remove();

	// 根据连线样式创建对应的元素
	if (props.linkStyle?.type === 'curve') {
		// 创建曲线连接（path元素）

		linksGroup
			.selectAll('.link')
			.data(validLinks as SimulationLinkType[])
			.enter()
			.append('path')
			.attr('class', 'link')
			.attr('fill', 'none')
			.attr('stroke', '#999')
			.attr('stroke-width', 1)
			.attr('stroke-dasharray', (d) => {
				d.isHierarchy = d.isHierarchy || relationTypeMap.value?.get(d.label)?.isHierarchy || false;
				return d.isHierarchy === true ? 'none' : '5,5';
			})
			.attr('marker-end', (d) => {
				d.isHierarchy = d.isHierarchy || relationTypeMap.value?.get(d.label)?.isHierarchy || false;
				return d.isHierarchy === true ? 'url(#arrowhead)' : 'none';
			})
			.attr('d', (d) => generateCurvePath(d as SimulationLinkType));

		// 在编辑模式下为连线添加双击事件
		if (props.isEdit) {
			linksGroup.selectAll('.link').style('cursor', 'pointer');
		}
	} else {
		// 创建直线连接（line元素）

		linksGroup
			.selectAll('.link')
			.data(validLinks as SimulationLinkType[])
			.enter()
			.append('line')
			.attr('class', 'link')
			.attr('stroke', '#999')
			.attr('stroke-width', 1)
			.attr('stroke-dasharray', (d) => (d.isHierarchy === true ? 'none' : '5,5'))
			.attr('marker-end', (d) => (d.isHierarchy === true ? 'url(#arrowhead)' : 'none'))
			.attr('x1', (d) => {
				const link = d as SimulationLinkType;
				const sourceRadius = (link.source.size || props.defaultNodeStyle.size) / 2;
				return getEdgePosition(link.source, link.target, sourceRadius).x;
			})
			.attr('y1', (d) => {
				const link = d as SimulationLinkType;
				const sourceRadius = (link.source.size || props.defaultNodeStyle.size) / 2;
				return getEdgePosition(link.source, link.target, sourceRadius).y;
			})
			.attr('x2', (d) => {
				const link = d as SimulationLinkType;
				const targetRadius = (link.target.size || props.defaultNodeStyle.size) / 2;
				return getEdgePosition(link.target, link.source, targetRadius).x;
			})
			.attr('y2', (d) => {
				const link = d as SimulationLinkType;
				const targetRadius = (link.target.size || props.defaultNodeStyle.size) / 2;
				return getEdgePosition(link.target, link.source, targetRadius).y;
			});

		// 在编辑模式下为连线添加双击事件
		if (props.isEdit) {
			linksGroup.selectAll('.link').style('cursor', 'pointer');
		}
	}

	// 添加连接标签（如果有）
	renderLinkLabels();
};

// 渲染连接标签
const renderLinkLabels = () => {
	const linksGroup = zoomGroup.value?.select('.links-group');
	if (!linksGroup) return;

	// 过滤有效且有标签的连接 - 使用预处理数据
	const validLinksWithLabels = validLinks.value.filter((d) => d.label);

	// 创建连接标签
	const labelElements = linksGroup
		.selectAll('.link-label')
		.data(validLinksWithLabels)
		.enter()
		.append('text')
		.attr('class', 'link-label')
		.text((d) => d.label)
		.attr('text-anchor', 'middle')
		.attr('font-size', '10px')
		.attr('fill', '#666')
		.attr('x', (d) => getLinkLabelPosition(d as SimulationLinkType).x)
		.attr('y', (d) => getLinkLabelPosition(d as SimulationLinkType).y)
		.classed('editable', props.isEdit);

	// 在编辑模式下添加双击事件
	if (props.isEdit) {
		labelElements.on('dblclick', (event, d) =>
			handleLinkLabelDoubleClick(event, d as SimulationLinkType)
		);
	}
};

// 处理连线标签双击事件
const handleLinkLabelDoubleClick = (event: MouseEvent, link: SimulationLinkType) => {
	event.preventDefault();
	event.stopPropagation();

	// 如果不是编辑模式，不响应双击
	if (!props.isEdit) {
		return;
	}

	// 隐藏右键菜单（如果有的话）
	hideContextMenu();
	openEditRelationDialog(link);
};

/** -------------------创建节点------------------- */
// 渲染节点 - 支持视窗裁剪优化
const renderNodes = () => {
	const nodesGroup = zoomGroup.value?.select('.nodes-group');
	if (!nodesGroup) return;

	// 使用视窗裁剪优化（在大数据量时）
	const visibleNodes = getVisibleNodes();

	const nodes = nodesGroup
		.selectAll('.node-group')
		.data(visibleNodes, (d) => (d as SimulationNodeType).id);

	// 移除多余的节点
	nodes.exit().remove();

	// 添加新节点
	const nodeEnter = nodes.enter().append('g').attr('class', 'node-group');

	// 为节点创建渐变和背景图
	visibleNodes.forEach((d) => {
		// 为有渐变配置的节点创建渐变
		if (d.gradientStops && Array.isArray(d.gradientStops) && d.gradientStops.length >= 2) {
			createNodeGradient(d);
		}

		// 为有背景图且未加载过的节点创建 pattern
		if (d.backgroundImg && !d._imageLoaded && !d._imageLoadFailed) {
			createNodePattern(d);
		}
	});

	// 节点圆圈
	nodeEnter
		.append('circle')
		.attr('class', (d) => {
			// 如果节点有背景图，添加特殊 class
			const hasBackgroundImg = d.backgroundImg && d._imageLoaded && !d._imageLoadFailed;
			return hasBackgroundImg ? 'node-circle has-background-img' : 'node-circle';
		})
		.attr('r', (d) => (d.size || 0) / 2)
		.attr('fill', (d) => getNodeFill(d))
		.style('cursor', 'move');

	// 合并和更新
	const nodeUpdate = (
		nodes as unknown as d3.Selection<SVGGElement, NodeItemType, SVGGElement, unknown>
	).merge(nodeEnter as unknown as d3.Selection<SVGGElement, NodeItemType, SVGGElement, unknown>);

	nodeUpdate
		.select('.node-circle')
		.attr('class', (d) => {
			// 更新时也要判断是否有背景图
			const hasBackgroundImg = d.backgroundImg && d._imageLoaded && !d._imageLoadFailed;
			return hasBackgroundImg ? 'node-circle has-background-img' : 'node-circle';
		})
		.attr('r', (d) => (d.size || 0) / 2)
		.attr('fill', (d) => getNodeFill(d));

	// 添加拖拽行为和交互事件
	nodeUpdate
		.call(createDragBehavior())
		.on('click', handleNodeClick)
		.on('contextmenu', handleNodeContextMenu)
		.on('mouseenter', handleNodeMouseEnter)
		.on('mouseleave', handleNodeMouseLeave);

	// 添加展开/收起按钮
	renderExpandCollapseButtons(nodeUpdate);
};

// 为节点创建渐变
const createNodeGradient = (node: SimulationNodeType) => {
	const gradientId = `gradient-${node.id}`;

	// 检查是否有渐变配置
	if (!node.gradientStops || !Array.isArray(node.gradientStops) || node.gradientStops.length < 2) {
		return null;
	}

	if (!svg.value) return null;

	let defs = svg.value.select('defs') as d3.Selection<SVGDefsElement, unknown, null, undefined>;
	if (defs.empty()) {
		defs = svg.value.append('defs') as d3.Selection<SVGDefsElement, unknown, null, undefined>;
	}

	// 移除旧的渐变（如果存在）
	defs.select(`#${gradientId}`).remove();

	const gradientType = node.gradientType || 'linear';

	if (gradientType === 'radial') {
		// 创建径向渐变
		const gradient = defs.append('radialGradient').attr('id', gradientId);

		// 设置径向渐变的中心点和半径
		// cx, cy: 渐变中心（默认 50%, 50%）
		// r: 渐变半径（默认 50%）
		gradient.attr('cx', '50%').attr('cy', '50%').attr('r', '50%');

		// 添加渐变色标
		node.gradientStops.forEach((stop) => {
			const stopElement = gradient
				.append('stop')
				.attr('offset', `${stop.offset * 100}%`)
				.attr('stop-color', stop.color);

			if (stop.opacity !== undefined) {
				stopElement.attr('stop-opacity', stop.opacity);
			}
		});
	} else {
		// 创建线性渐变
		const gradient = defs.append('linearGradient').attr('id', gradientId);

		// 设置渐变方向
		const gradientDir = node.gradientDir || [0, 0, 1, 0]; // 默认从左到右
		const [x1, y1, x2, y2] = gradientDir;
		gradient
			.attr('x1', `${x1 * 100}%`)
			.attr('y1', `${y1 * 100}%`)
			.attr('x2', `${x2 * 100}%`)
			.attr('y2', `${y2 * 100}%`);

		// 添加渐变色标
		node.gradientStops.forEach((stop) => {
			const stopElement = gradient
				.append('stop')
				.attr('offset', `${stop.offset * 100}%`)
				.attr('stop-color', stop.color);

			if (stop.opacity !== undefined) {
				stopElement.attr('stop-opacity', stop.opacity);
			}
		});
	}

	return gradientId;
};

// 为节点创建背景图 pattern
const createNodePattern = (node: SimulationNodeType) => {
	const patternId = `pattern-${node.id}`;

	// 使用 Image 对象预加载图片，检测加载状态
	const img = new Image();

	img.onload = () => {
		// 图片加载成功，创建 pattern
		if (!svg.value) return null;

		let defs = svg.value.select('defs') as d3.Selection<SVGDefsElement, unknown, null, undefined>;
		if (defs.empty()) {
			defs = svg.value.append('defs') as d3.Selection<SVGDefsElement, unknown, null, undefined>;
		}

		// 移除旧的 pattern（如果存在）
		defs.select(`#${patternId}`).remove();

		// 创建新的 pattern
		const pattern = defs
			.append('pattern')
			.attr('id', patternId)
			.attr('x', 0)
			.attr('y', 0)
			.attr('width', 1)
			.attr('height', 1)
			.attr('patternUnits', 'objectBoundingBox');

		// 添加图片
		pattern
			.append('image')
			.attr('x', 0)
			.attr('y', 0)
			.attr('width', node.size || 0)
			.attr('height', node.size || 0)
			.attr('preserveAspectRatio', 'xMidYMid slice')
			.attr('href', node.backgroundImg || '');

		// 标记图片已加载成功
		node._imageLoaded = true;

		// 只更新这个节点的 class 和填充，不触发完整的重新渲染
		zoomGroup.value
			?.selectAll('.node-group')
			.filter((d) => (d as SimulationNodeType).id === node.id)
			.select('.node-circle')
			.attr('class', 'node-circle has-background-img') // 添加背景图 class
			.attr('fill', getNodeFill(node));
	};

	img.onerror = () => {
		console.warn(`图片加载失败: ${node.backgroundImg}，将回退到渐变或纯色`);
		// 标记节点图片加载失败
		node._imageLoadFailed = true;
		node._imageLoaded = true; // 也标记为已加载，避免重试

		// 只更新这个节点的 class 和填充（会自动使用渐变或纯色）
		zoomGroup.value
			?.selectAll('.node-group')
			.filter((d) => (d as SimulationNodeType).id === node.id)
			.select('.node-circle')
			.attr('class', 'node-circle') // 移除背景图 class
			.attr('fill', getNodeFill(node));
	};

	// 开始加载图片
	img.src = node.backgroundImg || '';
};

// 获取节点的填充值（根据优先级：背景图 > 渐变 > 纯色）
const getNodeFill = (node: SimulationNodeType) => {
	// 优先级1: 背景图（如果有且加载成功）
	if (node.backgroundImg && node._imageLoaded && !node._imageLoadFailed) {
		return `url(#pattern-${node.id})`;
	}

	// 优先级2: 渐变（如果有配置）
	if (node.gradientStops && Array.isArray(node.gradientStops) && node.gradientStops.length >= 2) {
		return `url(#gradient-${node.id})`;
	}

	// 优先级3: 纯色
	return node.color || '';
};

/** -------------------展开/收起功能------------------- */
// 渲染展开/收起按钮
const renderExpandCollapseButtons = (
	nodeSelection: d3.Selection<SVGGElement, SimulationNodeType, SVGGElement, unknown>
) => {
	// 为每个有子节点的节点添加按钮
	nodeSelection.each((d, i, nodes) => {
		const nodeGroup = d3.select(nodes[i]);
		const nodeId = d.id;

		// 检查节点是否在排除列表中
		const excludeSet = new Set(props.excludeNodeList.map((id: string) => String(id)));
		if (excludeSet.has(String(nodeId))) {
			// 在排除列表中，移除按钮（如果存在）
			nodeGroup.select('.expand-collapse-button').remove();
			return;
		}

		const children = nodeChildrenMap.value.get(nodeId);
		const hasChildren = children && children.size > 0;

		if (!hasChildren) {
			// 没有子节点，移除按钮（如果存在）
			nodeGroup.select('.expand-collapse-button').remove();
			return;
		}

		const isExpanded = nodeExpandState.value.get(nodeId) !== false; // 默认为展开
		const buttonGroup = nodeGroup.select('.expand-collapse-button');

		if (buttonGroup.empty()) {
			// 创建按钮组
			const button = nodeGroup.append('g').attr('class', 'expand-collapse-button');

			// 创建圆圈背景
			button
				.append('circle')
				.attr('class', 'expand-collapse-circle')
				.attr('r', 6)
				.attr('fill', '#fff')
				.attr('stroke', '#ccc')
				.attr('stroke-width', 1)
				.style('cursor', 'pointer')
				.on('click', (event: MouseEvent) => {
					event.stopPropagation();
					toggleNodeExpand(nodeId);
				});

			// 创建符号（加号/减号或数字）
			button.append('g').attr('class', 'expand-collapse-icon');
		}

		// 更新按钮位置和内容
		const button = nodeGroup.select('.expand-collapse-button');
		const nodeSize = d.size || props.defaultNodeStyle?.size || 0;
		const buttonX = nodeSize / 2 + 6; // 按钮在节点右侧
		const buttonY = 0;

		button.attr('transform', `translate(${buttonX}, ${buttonY})`);

		// 更新按钮内容
		const iconGroup = button.select('.expand-collapse-icon');
		iconGroup.selectAll('*').remove();

		if (isExpanded) {
			// 展开状态：鼠标悬停时显示减号
			button.style('opacity', 0).style('pointer-events', 'none');
			// 减号（水平线）
			iconGroup
				.append('line')
				.attr('x1', -3)
				.attr('y1', 0)
				.attr('x2', 3)
				.attr('y2', 0)
				.attr('stroke', '#666')
				.attr('stroke-width', 2)
				.attr('stroke-linecap', 'round');
		} else {
			// 收起状态：常显展开按钮，显示数字
			button.style('opacity', 1).style('pointer-events', 'all');
			// 圆圈
			iconGroup
				.append('circle')
				.attr('r', 6)
				.attr('fill', '#fff')
				.attr('stroke', '#4a90e2')
				.attr('stroke-width', 1);
			// 数字
			iconGroup
				.append('text')
				.attr('text-anchor', 'middle')
				.attr('dominant-baseline', 'middle')
				.attr('font-size', '8px')
				.attr('font-weight', 'bold')
				.attr('fill', '#4a90e2')
				.text(children!.size);
		}
	});
};

// 切换节点展开/收起状态
const toggleNodeExpand = (nodeId: string) => {
	const currentState = nodeExpandState.value.get(nodeId) !== false;
	const newState = !currentState;
	nodeExpandState.value.set(nodeId, newState);

	// 更新子节点和连接的可见性
	updateNodeVisibility();

	// 重新渲染按钮
	const nodesGroup = zoomGroup.value?.select('.nodes-group');
	if (nodesGroup) {
		const nodeUpdate = nodesGroup.selectAll('.node-group') as d3.Selection<
			SVGGElement,
			SimulationNodeType,
			SVGGElement,
			unknown
		>;
		renderExpandCollapseButtons(nodeUpdate);
	}
};

// 显示收起按钮（鼠标悬停时）
const showCollapseButton = (nodeId: string) => {
	const children = nodeChildrenMap.value.get(nodeId);
	const hasChildren = children && children.size > 0;
	if (!hasChildren) return;

	const isExpanded = nodeExpandState.value.get(nodeId) !== false;
	if (!isExpanded) return; // 收起状态不显示

	const nodeGroups = zoomGroup.value?.selectAll('.node-group') as d3.Selection<
		SVGGElement,
		SimulationNodeType,
		SVGGElement,
		unknown
	>;
	if (nodeGroups) {
		const nodeGroup = nodeGroups.filter((d) => d.id === nodeId);
		if (!nodeGroup.empty()) {
			const button = nodeGroup.select('.expand-collapse-button');
			if (!button.empty()) {
				button.style('opacity', 1).style('pointer-events', 'all');
			}
		}
	}
};

// 隐藏收起按钮（鼠标离开时）
const hideCollapseButtons = () => {
	zoomGroup.value?.selectAll('.expand-collapse-button').each((d, i, nodes) => {
		const button = d3.select(nodes[i]);
		const nodeId = (d as SimulationNodeType).id;
		const isExpanded = nodeExpandState.value.get(nodeId) !== false;
		if (isExpanded) {
			button.style('opacity', 0).style('pointer-events', 'none');
		}
	});
};

// 展开相关节点（用于高亮时自动展开收起的节点）
// 参数：nodeIds - 需要展开的节点ID集合
const expandRelatedNodes = (nodeIds: Set<string>) => {
	if (!nodeIds || nodeIds.size === 0) return;

	// 递归向上查找并展开父节点
	const expandParents = (nodeId: string, visited = new Set<string>()) => {
		if (visited.has(nodeId)) return; // 防止循环
		visited.add(nodeId);

		const parentId = nodeParentMap.value.get(nodeId);
		if (parentId) {
			// 如果父节点是收起的，展开它
			const isExpanded = nodeExpandState.value.get(parentId) !== false;
			if (!isExpanded) {
				nodeExpandState.value.set(parentId, true);
			}
			// 继续向上查找父节点的父节点
			expandParents(parentId, visited);
		}
	};

	// 为每个需要展开的节点，向上查找并展开其父节点
	nodeIds.forEach((nodeId) => {
		expandParents(nodeId);
	});

	// 更新可见性并重新渲染按钮
	updateNodeVisibility();
	const nodesGroup = zoomGroup.value?.select('.nodes-group');
	if (nodesGroup) {
		const nodeUpdate = nodesGroup.selectAll('.node-group') as d3.Selection<
			SVGGElement,
			SimulationNodeType,
			SVGGElement,
			unknown
		>;
		renderExpandCollapseButtons(nodeUpdate);
	}
};

// 获取当前隐藏的节点ID集合（用于其他函数判断节点是否可见）
const getHiddenNodeIds = (): Set<string> => {
	const hiddenNodeIds = new Set<string>();

	// 递归收集应该隐藏的节点
	// 规则：如果一个节点是收起的，它的所有后代节点（递归）都应该被隐藏
	// 参数：nodeId - 要检查的节点ID，forceHide - 是否强制隐藏（父节点是收起的）
	const collectHiddenNodes = (nodeId: string, forceHide = false) => {
		const isExpanded = nodeExpandState.value.get(nodeId) !== false;

		// 如果强制隐藏（父节点是收起的）或者当前节点是收起的
		if (forceHide || !isExpanded) {
			const children = nodeChildrenMap.value.get(nodeId);
			if (children) {
				children.forEach((childId) => {
					// 添加子节点到隐藏列表
					hiddenNodeIds.add(childId);
					// 递归收集子节点的所有后代（强制隐藏，因为父节点是收起的）
					collectHiddenNodes(childId, true);
				});
			}
		} else {
			// 节点是展开的，检查它的子节点
			// 如果某个子节点是收起的，那么该子节点的所有后代应该被隐藏（但不隐藏子节点本身）
			const children = nodeChildrenMap.value.get(nodeId);
			if (children) {
				children.forEach((childId) => {
					const childIsExpanded = nodeExpandState.value.get(childId) !== false;
					if (!childIsExpanded) {
						// 子节点是收起的，收集该子节点的所有后代（递归），但不隐藏子节点本身
						collectHiddenNodes(childId, true);
					} else {
						// 子节点是展开的，继续检查子节点的子节点
						collectHiddenNodes(childId, false);
					}
				});
			}
		}
	};

	// 遍历所有有子节点的节点，从根节点开始收集隐藏节点
	nodeChildrenMap.value.forEach((children, nodeId) => {
		collectHiddenNodes(nodeId, false);
	});

	return hiddenNodeIds;
};

// 更新节点和连接的可见性
const updateNodeVisibility = () => {
	// 获取所有应该隐藏的节点ID
	const hiddenNodeIds = getHiddenNodeIds();

	// 更新节点可见性
	(
		zoomGroup.value?.selectAll('.node-group') as d3.Selection<
			SVGGElement,
			SimulationNodeType,
			SVGGElement,
			unknown
		>
	).style('display', (d) => {
		return hiddenNodeIds.has(d.id) ? 'none' : 'block';
	});

	// 更新连接可见性
	(
		zoomGroup.value?.selectAll('.link') as d3.Selection<
			SVGPathElement | SVGLineElement,
			SimulationLinkType,
			SVGGElement,
			unknown
		>
	).style('display', (d) => {
		const sourceId = typeof d.source === 'string' ? d.source : (d.source as SimulationNodeType).id;
		const targetId = typeof d.target === 'string' ? d.target : (d.target as SimulationNodeType).id;
		return hiddenNodeIds.has(sourceId) || hiddenNodeIds.has(targetId) ? 'none' : 'block';
	});

	// 更新连接标签可见性
	(
		zoomGroup.value?.selectAll('.link-label') as d3.Selection<
			SVGTextElement,
			SimulationLinkType,
			SVGGElement,
			unknown
		>
	).style('display', (d) => {
		const sourceId = typeof d.source === 'string' ? d.source : (d.source as SimulationNodeType).id;
		const targetId = typeof d.target === 'string' ? d.target : (d.target as SimulationNodeType).id;
		return hiddenNodeIds.has(sourceId) || hiddenNodeIds.has(targetId) ? 'none' : 'block';
	});

	// 更新节点标签可见性
	(
		zoomGroup.value?.selectAll('.node-label-group') as d3.Selection<
			SVGGElement,
			SimulationNodeType,
			SVGGElement,
			unknown
		>
	).style('display', (d) => {
		return hiddenNodeIds.has(d.id) ? 'none' : 'block';
	});
};

/** -------------------创建节点标签------------------- */
// 渲染节点标签 - 支持视窗裁剪优化和动态位置
const renderLabels = () => {
	const labelsGroup = zoomGroup.value?.select('.labels-group');
	if (!labelsGroup) return;

	// 使用视窗裁剪优化（在大数据量时）
	const visibleNodes = getVisibleNodes();

	const labels = labelsGroup
		?.selectAll('.node-label-group')
		.data(visibleNodes, (d) => (d as SimulationNodeType).id);

	labels.exit().remove();

	// 为每个节点创建一个 g 元素作为容器
	const labelEnter = labels.enter().append('g').attr('class', 'node-label-group');

	const labelUpdate = (
		labels as unknown as d3.Selection<SVGGElement, NodeItemType, SVGGElement, unknown>
	).merge(labelEnter as unknown as d3.Selection<SVGGElement, NodeItemType, SVGGElement, unknown>);

	// 清除现有内容
	labelUpdate.selectAll('*').remove();

	// 为每个节点渲染标签
	labelUpdate.each((d, i, nodes) => {
		const labelGroup = d3.select(nodes[i]);
		const nodeType = nodeTypeMap.value?.get(d.type);
		const textPosition = nodeType?.textPosition || 'bottom'; // 默认在底部

		if (textPosition === 'center') {
			// 中心位置：需要换行处理
			renderCenterLabel(labelGroup, d as SimulationNodeType);
		} else {
			// 底部位置：单行文本
			renderBottomLabel(labelGroup, d as SimulationNodeType);
		}
	});

	// 在编辑模式下添加双击事件
	if (props.isEdit) {
		labelUpdate.on('dblclick', handleLabelDoubleClick);
	} else {
		labelUpdate.on('dblclick', null); // 清除双击事件
	}
};

// 渲染中心位置的标签（支持换行）
const renderCenterLabel = (
	labelGroup: d3.Selection<SVGGElement, unknown, null, undefined>,
	node: SimulationNodeType
) => {
	const nodeSize = node.size || props.defaultNodeStyle?.size || 0;
	const maxWidth = nodeSize * 0.8; // 文本最大宽度为节点直径的80%
	const fontSize = 10;
	const lineHeight = 12;

	// 将文本按字符分割并计算换行
	const text = node.label || '';
	const lines = wrapText(text, maxWidth, fontSize);

	// 计算总高度并使其垂直居中
	const totalHeight = lines.length * lineHeight;
	const startY = -totalHeight / 2 + lineHeight / 2;

	// 给 labelGroup 添加多行标签的 class
	labelGroup.classed('multi-line-label', true);

	// 为每一行创建 text 元素
	lines.forEach((line, index) => {
		labelGroup
			.append('text')
			.attr('class', 'node-label node-label-center')
			.attr('x', 0)
			.attr('y', startY + index * lineHeight)
			.attr('text-anchor', 'middle')
			.attr('dominant-baseline', 'middle')
			.attr('font-size', fontSize)
			.attr('fill', '#fff')
			.attr('font-weight', '500')
			.classed('editable', props.isEdit)
			.text(line);
	});
};

// 渲染底部位置的标签（单行）
const renderBottomLabel = (
	labelGroup: d3.Selection<SVGGElement, unknown, null, undefined>,
	node: SimulationNodeType
) => {
	const nodeSize = node.size || props.defaultNodeStyle?.size || 0;
	const offsetY = nodeSize / 2 + 15;

	labelGroup
		.append('text')
		.attr('class', 'node-label node-label-bottom')
		.attr('x', 0)
		.attr('y', offsetY)
		.attr('text-anchor', 'middle')
		.attr('dominant-baseline', 'central')
		.classed('editable', props.isEdit)
		.text(node.label);
};

/** -------------------节点事件（拖拽、悬停、点击）------------------- */
/** -----拖拽事件----- */
// 拖拽状态
const draggedNode = ref<SimulationNodeType | null>(null);

// 创建拖拽行为
const createDragBehavior = () => {
	return d3
		.drag<SVGGElement, SimulationNodeType>()
		.on('start', handleDragStart)
		.on('drag', handleDrag)
		.on('end', handleDragEnd);
};

// 拖拽开始
const handleDragStart = (
	event: d3.D3DragEvent<SVGGElement, SimulationNodeType, SimulationNodeType>,
	node: SimulationNodeType
) => {
	// 隐藏节点信息气泡框
	hideNodeTooltip();

	if (!event.active) simulation.value?.alphaTarget(0.3).restart();

	draggedNode.value = node;
	node.fx = node.x;
	node.fy = node.y;

	// 拖拽时清除悬停状态
	clearHoverTimer();
	clearHoverHighlight();
};

// 拖拽中
const handleDrag = (
	event: d3.D3DragEvent<SVGGElement, SimulationNodeType, SimulationNodeType>,
	node: SimulationNodeType
) => {
	node.fx = event.x;
	node.fy = event.y;
};

// 拖拽结束
const handleDragEnd = (
	event: d3.D3DragEvent<SVGGElement, SimulationNodeType, SimulationNodeType>,
	node: SimulationNodeType
) => {
	if (!event.active) simulation.value?.alphaTarget(0);

	// 保持节点固定在拖拽位置
	node.fx = event.x;
	node.fy = event.y;

	draggedNode.value = null;
};

// 交互状态
const hoverTimer = ref<ReturnType<typeof setTimeout> | null>(null);
const hoveredNode = ref<SimulationNodeType | null>(null);
const focusedNode = ref<SimulationNodeType | null>(null);

/** -------------------节点信息气泡框------------------- */
// 气泡框相关数据
const nodeTooltipRef = ref<HTMLElement | null>(null);
const tooltipVisible = ref(false);
const tooltipStyle = ref<{ left?: string; top?: string; transform?: string }>({});
const tooltipData = ref<{ name: string; type: string }>({ name: '', type: '' });
// tooltip 隐藏延迟定时器
let tooltipHideTimer: ReturnType<typeof setTimeout> | null = null;

/** -----点击事件----- */
// 节点点击处理
const handleNodeClick = (event: MouseEvent, node: SimulationNodeType) => {
	event.stopPropagation();

	// 隐藏节点信息气泡框
	hideNodeTooltip();

	// 如果点击的是当前焦点节点，则取消焦点
	if (focusedNode.value && focusedNode.value.id === node.id) {
		unfocus();
		return;
	}

	// 设置新的焦点节点
	focusOnNode(node);
	emit('node-click', node as NetworkNodeElType);
};

// 取消焦点
const unfocus = () => {
	focusedNode.value = null;
	clearHighlight();
};

// 聚焦到节点
const focusOnNode = (node: SimulationNodeType) => {
	// 清除之前的高亮
	clearHighlight();

	// 设置新焦点
	focusedNode.value = node;

	// 高亮节点和相关连线
	const nodeIds = highlightNode(node);
	const nds = nodes.value.filter((node: SimulationNodeType) => {
		// 只包含高亮的节点，且排除收起的节点
		return nodeIds.has(node.id);
	});
	// 检查点击的节点是否在排除列表中
	const excludeSet = new Set(props.excludeNodeList.map((id: string) => String(id)));
	const useDefaultCenter = excludeSet.has(String(node.id));
	// 将节点移动到画布中心
	centerToNodes(nds as SimulationNodeType[], useDefaultCenter);
};

// 高亮节点和相关元素 - 优化版本，使用邻居缓存
const highlightNode = (node: SimulationNodeType) => {
	const connectedNodeIds = new Set<string>([node.id]);

	// 获取隐藏的节点ID集合，排除收起的节点
	const hiddenNodeIds = getHiddenNodeIds();

	// 使用预计算的邻居表，避免遍历所有连线
	const neighbors = nodeNeighbors.value?.get(node.id);
	if (neighbors) {
		neighbors.forEach((neighborId: string) => {
			// 只添加未隐藏的邻居节点
			if (!hiddenNodeIds.has(neighborId)) {
				connectedNodeIds.add(neighborId);
			}
		});
	}

	// 高亮节点
	(
		zoomGroup.value?.selectAll('.node-group') as d3.Selection<
			SVGGElement,
			SimulationNodeType,
			SVGGElement,
			unknown
		>
	)
		.classed('highlighted', (d) => connectedNodeIds.has(d.id))
		.classed('dimmed', (d) => !connectedNodeIds.has(d.id));

	// 高亮连接线
	(
		zoomGroup.value?.selectAll('.link') as d3.Selection<
			SVGPathElement | SVGLineElement,
			SimulationLinkType,
			SVGGElement,
			unknown
		>
	)
		.classed('highlighted', (d) => {
			const sourceId = d.source.id || d.source;
			const targetId = d.target.id || d.target;
			return (
				(sourceId === node.id || targetId === node.id) &&
				!hiddenNodeIds.has(sourceId) &&
				!hiddenNodeIds.has(targetId)
			);
		})
		.classed('dimmed', (d) => {
			const sourceId = d.source.id || d.source;
			const targetId = d.target.id || d.target;
			return (
				!(sourceId === node.id || targetId === node.id) ||
				hiddenNodeIds.has(sourceId) ||
				hiddenNodeIds.has(targetId)
			);
		})
		.attr('marker-end', (d) => {
			const sourceId = d.source.id || d.source;
			const targetId = d.target.id || d.target;
			const isConnected =
				(sourceId === node.id || targetId === node.id) &&
				!hiddenNodeIds.has(sourceId) &&
				!hiddenNodeIds.has(targetId);
			if (d.isHierarchy === true) {
				return isConnected ? 'url(#arrowhead-highlight)' : 'url(#arrowhead)';
			} else {
				return 'none';
			}
		});

	// 高亮连接标签
	(
		zoomGroup.value?.selectAll('.link-label') as d3.Selection<
			SVGTextElement,
			SimulationLinkType,
			SVGGElement,
			unknown
		>
	)
		.classed('highlighted', (d) => {
			const sourceId = d.source.id || d.source;
			const targetId = d.target.id || d.target;
			return (
				(sourceId === node.id || targetId === node.id) &&
				!hiddenNodeIds.has(sourceId) &&
				!hiddenNodeIds.has(targetId)
			);
		})
		.classed('dimmed', (d) => {
			const sourceId = d.source.id || d.source;
			const targetId = d.target.id || d.target;
			return (
				!(sourceId === node.id || targetId === node.id) ||
				hiddenNodeIds.has(sourceId) ||
				hiddenNodeIds.has(targetId)
			);
		});

	// 高亮节点标签组
	(
		zoomGroup.value?.selectAll('.node-label-group') as d3.Selection<
			SVGGElement,
			SimulationNodeType,
			SVGGElement,
			unknown
		>
	)
		.classed('highlighted', (d) => connectedNodeIds.has(d.id))
		.classed('dimmed', (d) => !connectedNodeIds.has(d.id));

	return connectedNodeIds;
};

/** -----悬停事件----- */
// 显示节点信息气泡框
const showNodeTooltip = (nodeElement: HTMLElement, name: string, type: string) => {
	// 清除之前的隐藏定时器
	if (tooltipHideTimer) {
		clearTimeout(tooltipHideTimer);
		tooltipHideTimer = null;
	}

	// 使用 typeMap 将类型转换为中文
	const typeLabel = props.typeMap?.get(type) || type;
	tooltipData.value = { name, type: typeLabel };

	// 获取节点元素的位置信息
	const nodeRect = nodeElement.getBoundingClientRect();
	// 计算节点顶部中心位置
	const nodeCenterX = nodeRect.left + nodeRect.width / 2;
	const nodeTopY = nodeRect.top;

	const offset = 10; // 距离节点顶部的偏移量

	// 计算 tooltip 位置：节点顶部中心位置上方
	// 使用 transform: translate(-50%, -100%) 实现居中和向上偏移
	tooltipStyle.value = {
		left: `${nodeCenterX}px`,
		top: `${nodeTopY - offset}px`,
		transform: 'translate(-50%, -100%)' // 水平居中，垂直向上偏移100%
	};

	tooltipVisible.value = true;
};

// 隐藏节点信息气泡框（带延迟，避免快速移动时闪烁）
const hideNodeTooltip = () => {
	if (tooltipHideTimer) {
		clearTimeout(tooltipHideTimer);
	}
	tooltipHideTimer = setTimeout(() => {
		tooltipVisible.value = false;
		tooltipHideTimer = null;
	}, 100); // 100ms 延迟，避免快速移动时闪烁
};

// 节点鼠标进入处理
const handleNodeMouseEnter = (event: MouseEvent, node: SimulationNodeType) => {
	// 如果正在拖拽或已有焦点节点，则不处理悬停
	if (draggedNode.value || focusedNode.value) return;

	// 清除之前的定时器
	clearHoverTimer();

	// 设置延迟定时器，避免快速滑动时频繁触发
	hoverTimer.value = setTimeout(() => {
		hoveredNode.value = node;
		highlightNodeOnHover(node);
		// 显示展开节点的收起按钮
		showCollapseButton(node.id);

		// 显示节点信息气泡框
		// 事件绑定在 .node-group 上，所以 event.target  就是节点元素
		const nodeElement = event.target as HTMLElement;
		if (nodeElement) {
			const nodeName = node.label || '';
			const nodeType = node.type || '';
			showNodeTooltip(nodeElement, nodeName, nodeType);
		}
	}, 200); // 200ms 延迟
};

// 悬停高亮节点和相关元素 - 优化版本，使用邻居缓存
const highlightNodeOnHover = (node: SimulationNodeType) => {
	const connectedNodeIds = new Set([node.id]);

	// 使用预计算的邻居表，避免遍历所有连线
	const neighbors = nodeNeighbors.value?.get(node.id);
	if (neighbors) {
		neighbors.forEach((neighborId: string) => {
			connectedNodeIds.add(neighborId);
		});
	}

	// 悬停高亮节点
	(
		zoomGroup.value?.selectAll('.node-group') as d3.Selection<
			SVGGElement,
			SimulationNodeType,
			SVGGElement,
			unknown
		>
	)
		.classed('hover-highlighted', (d) => connectedNodeIds.has(d.id))
		.classed('hover-dimmed', (d) => !connectedNodeIds.has(d.id));

	// 悬停高亮连接线
	(
		zoomGroup.value?.selectAll('.link') as d3.Selection<
			SVGPathElement | SVGLineElement,
			SimulationLinkType,
			SVGGElement,
			unknown
		>
	)
		.classed('hover-highlighted', (d) => {
			const sourceId = d.source.id || d.source;
			const targetId = d.target.id || d.target;
			return sourceId === node.id || targetId === node.id;
		})
		.classed('hover-dimmed', (d) => {
			const sourceId = d.source.id || d.source;
			const targetId = d.target.id || d.target;
			return !(sourceId === node.id || targetId === node.id);
		})
		.attr('marker-end', (d) => {
			const sourceId = d.source.id || d.source;
			const targetId = d.target.id || d.target;
			const isConnected = sourceId === node.id || targetId === node.id;
			if (d.isHierarchy === true) {
				return isConnected ? 'url(#arrowhead-highlight)' : 'url(#arrowhead)';
			} else {
				return 'none';
			}
		});

	// 悬停高亮连接标签
	(
		zoomGroup.value?.selectAll('.link-label') as d3.Selection<
			SVGTextElement,
			SimulationLinkType,
			SVGGElement,
			unknown
		>
	)
		.classed('hover-highlighted', (d) => {
			const sourceId = d.source.id || d.source;
			const targetId = d.target.id || d.target;
			return sourceId === node.id || targetId === node.id;
		})
		.classed('hover-dimmed', (d) => {
			const sourceId = d.source.id || d.source;
			const targetId = d.target.id || d.target;
			return !(sourceId === node.id || targetId === node.id);
		});

	// 悬停高亮节点标签组
	(
		zoomGroup.value?.selectAll('.node-label-group') as d3.Selection<
			SVGGElement,
			SimulationNodeType,
			SVGGElement,
			unknown
		>
	)
		.classed('hover-highlighted', (d) => connectedNodeIds.has(d.id))
		.classed('hover-dimmed', (d) => !connectedNodeIds.has(d.id));
};

// 节点鼠标离开处理
const handleNodeMouseLeave = () => {
	// 如果正在拖拽或已有焦点节点，则不处理悬停
	if (draggedNode.value || focusedNode.value) return;

	// 清除定时器和悬停高亮
	clearHoverTimer();
	clearHoverHighlight();
	// 隐藏收起按钮
	hideCollapseButtons();
	// 隐藏节点信息气泡框
	hideNodeTooltip();
};

/** -----清除相关----- */
// 清除悬停定时器
const clearHoverTimer = () => {
	if (hoverTimer.value) {
		clearTimeout(hoverTimer.value);
		hoverTimer.value = null;
	}
};

// 清除tick定时器
const clearTickTimer = () => {
	if (tickTimer.value) {
		cancelAnimationFrame(tickTimer.value);
		tickTimer.value = null;
	}
};

// 清除点击高亮
const clearHighlight = () => {
	zoomGroup.value
		?.selectAll('.node-group, .link, .link-label, .node-label-group')
		.classed('highlighted', false)
		.classed('dimmed', false);

	// 恢复默认箭头（根据isHierarchy属性）
	zoomGroup.value
		?.selectAll('.link')
		.attr('marker-end', (d) =>
			(d as SimulationLinkType).isHierarchy === true ? 'url(#arrowhead)' : 'none'
		);
};

// 清除悬停高亮
const clearHoverHighlight = () => {
	hoveredNode.value = null;
	zoomGroup.value
		?.selectAll('.node-group, .link, .link-label, .node-label-group')
		.classed('hover-highlighted', false)
		.classed('hover-dimmed', false);

	// 恢复默认箭头（如果没有焦点节点）
	if (!focusedNode.value) {
		zoomGroup.value
			?.selectAll('.link')
			.attr('marker-end', (d) =>
				(d as SimulationLinkType).isHierarchy === true ? 'url(#arrowhead)' : 'none'
			);
	}
};

/** -------------------获取位置信息------------------- */
// 计算节点边缘位置
const getEdgePosition = (
	sourceNode: SimulationNodeType,
	targetNode: SimulationNodeType,
	radius: number
): { x: number; y: number } => {
	const sourceX = sourceNode.x ?? 0;
	const sourceY = sourceNode.y ?? 0;
	const targetX = targetNode.x ?? 0;
	const targetY = targetNode.y ?? 0;

	const dx = targetX - sourceX;
	const dy = targetY - sourceY;
	const distance = Math.sqrt(dx * dx + dy * dy);

	// 避免除零错误
	if (distance === 0) {
		return { x: sourceX, y: sourceY };
	}

	// 计算单位向量
	const unitX = dx / distance;
	const unitY = dy / distance;

	// 返回节点边缘位置
	return {
		x: sourceX + unitX * radius,
		y: sourceY + unitY * radius
	};
};

// 获取连接标签位置
const getLinkLabelPosition = (linkData: SimulationLinkType): { x: number; y: number } => {
	const sourceRadius = (linkData.source.size || props.defaultNodeStyle.size) / 2;
	const targetRadius = (linkData.target.size || props.defaultNodeStyle.size) / 2;

	const sourceEdge = getEdgePosition(linkData.source, linkData.target, sourceRadius);
	const targetEdge = getEdgePosition(linkData.target, linkData.source, targetRadius);

	if (props.linkStyle.type === 'curve') {
		// 对于曲线，标签放在贝塞尔曲线的中点
		const midX = (sourceEdge.x + targetEdge.x) / 2;
		const midY = (sourceEdge.y + targetEdge.y) / 2;

		const dx = targetEdge.x - sourceEdge.x;
		const dy = targetEdge.y - sourceEdge.y;
		const distance = Math.sqrt(dx * dx + dy * dy);

		if (distance === 0) {
			return { x: midX, y: midY };
		}

		// 计算垂直于连线的向量
		const perpX = -dy / distance;
		const perpY = dx / distance;

		// 根据curvature参数计算标签位置（在曲线的中间点）
		const offset = distance * props.linkStyle.curvature * 0.5; // 标签位置在控制点和直线中点之间
		return {
			x: midX + perpX * offset,
			y: midY + perpY * offset
		};
	} else {
		// 对于直线，标签放在直线中点
		return {
			x: (sourceEdge.x + targetEdge.x) / 2,
			y: (sourceEdge.y + targetEdge.y) / 2
		};
	}
};

/** -------------------视窗裁剪优化相关------------------- */
// 计算当前视窗边界（用于视窗裁剪）
const calculateViewBox = () => {
	const transform = d3.zoomTransform(svg.value?.node() as SVGSVGElement);
	return {
		x: -transform.x / transform.k,
		y: -transform.y / transform.k,
		width: width.value / transform.k,
		height: height.value / transform.k
	};
};

// 获取可见连线（用于视窗裁剪优化）
const getVisibleLinks = () => {
	// 只有在节点数量较大时才启用视窗裁剪
	if (nodes.value.length <= 500) {
		return validLinks.value;
	}

	const viewBox = calculateViewBox();
	return validLinks.value.filter((link) => {
		const sourceId = (link.source as unknown as SimulationNodeType).id || link.source;
		const targetId = (link.target as unknown as SimulationNodeType).id || link.target;
		const sourceNode = nodes.value.find((n) => n.id === sourceId);
		const targetNode = nodes.value.find((n) => n.id === targetId);

		// 连线可见的条件：至少一个节点在视窗内
		return (
			sourceNode &&
			targetNode &&
			(isNodeVisible(sourceNode, viewBox) || isNodeVisible(targetNode, viewBox))
		);
	});
};

// 获取可见节点（用于视窗裁剪优化）
const getVisibleNodes = (): NodeItemType[] => {
	// 只有在节点数量较大时才启用视窗裁剪
	if (nodes.value.length <= 500) {
		return nodes.value;
	}

	const viewBox = calculateViewBox();
	return nodes.value.filter((node) => isNodeVisible(node, viewBox));
};

// 检查节点是否在视窗内（用于视窗裁剪）
const isNodeVisible = (
	node: SimulationNodeType,
	viewBox: { x: number; y: number; width: number; height: number } | null = null
) => {
	const vbox = viewBox || lastViewBox.value || calculateViewBox();
	const nodeRadius = (node.size || props.defaultNodeStyle.size) / 2;
	const padding = 50; // 额外填充，确保边缘节点也被渲染

	return (
		node.x !== undefined &&
		node.y !== undefined &&
		node.x >= vbox.x - nodeRadius - padding &&
		node.x <= vbox.x + vbox.width + nodeRadius + padding &&
		node.y >= vbox.y - nodeRadius - padding &&
		node.y <= vbox.y + vbox.height + nodeRadius + padding
	);
};

/** -------------------添加、编辑节点相关------------------- */
// 右键菜单
const contextMenu = ref<ContextMenuType>({
	visible: false,
	x: 0,
	y: 0,
	currentNode: null
});

// 右键添加节点
const handleAddNode = () => {
	const contextNode = contextMenu.value.currentNode as SimulationNodeType;
	hideContextMenu();
	openAddNodeDialog(contextNode);
};

// 右键编辑当前节点
const handleEditNode = () => {
	const contextNode = contextMenu.value.currentNode as SimulationNodeType;
	hideContextMenu();
	openEditNodeDialog(contextNode);
};

// 右键删除当前节点，并通知父级删除操作
const handleDeleteNode = () => {
	const node = contextMenu.value.currentNode as SimulationNodeType;
	ElMessageBox.confirm(`确定要删除节点"${node.label}"吗？`, '删除确认', {
		confirmButtonText: '确定',
		cancelButtonText: '取消',
		type: 'warning'
	})
		.then(() => {
			removeNodeById(node.id);
			emit('delete-node', node);
		})
		.catch(() => {
			// 用户取消删除
		});
	hideContextMenu();
};

// 画布点击处理
const handleCanvasClick = () => {
	hideContextMenu();
	unfocus();
};

// 隐藏右键菜单
const hideContextMenu = () => {
	contextMenu.value.visible = false;
	contextMenu.value.currentNode = null;
};

// 设置全局事件监听
const setupEventListeners = () => {
	document.addEventListener('click', handleDocumentClick);
};

// 移除全局事件监听
const removeEventListeners = () => {
	document.removeEventListener('click', handleDocumentClick);
};

// 文档点击处理
const handleDocumentClick = (event: MouseEvent) => {
	if (!containerRef.value?.contains(event.target as Node)) {
		hideContextMenu();
	}
};

// 节点右键处理
const handleNodeContextMenu = (event: MouseEvent, node: SimulationNodeType) => {
	event.preventDefault();
	event.stopPropagation();

	// 如果不是编辑模式，不显示右键菜单
	if (!props.isEdit) {
		return;
	}

	const containerRect = containerRef.value?.getBoundingClientRect();
	if (containerRect) {
		contextMenu.value = {
			visible: true,
			x: event.clientX - containerRect.left,
			y: event.clientY - containerRect.top,
			currentNode: node
		};
	}
};

// 处理节点标签双击事件
const handleLabelDoubleClick = (event: MouseEvent, node: SimulationNodeType) => {
	event.preventDefault();
	event.stopPropagation();

	// 如果不是编辑模式，不响应双击
	if (!props.isEdit) {
		return;
	}

	// 隐藏右键菜单（如果有的话）
	hideContextMenu();
	openEditNodeDialog(node);
};

// 节点编辑弹框
const nodeEditDialog = ref<NodeEditDialogType>({
	visible: false,
	isAdd: false,
	form: {
		nodeId: null,
		nodeName: '',
		nodeType: '',
		relations: []
	}
});
const currentEditNode = ref<SimulationNodeType | null>(null);
const currentNodeId = computed(() => {
	if (nodeEditDialog.value.isAdd) {
		return '__NEW_NODE__';
	} else {
		return nodeEditDialog.value.form.nodeId;
	}
});
const currentNodeLabel = computed(() => {
	if (nodeEditDialog.value.isAdd) {
		return nodeEditDialog.value.form.nodeName || '新建节点';
	} else {
		return nodeEditDialog.value.form.nodeName || '当前节点';
	}
});
const availableNodes = computed(() => {
	// 这个计算属性现在主要用于内部逻辑
	let nds: SimulationNodeType[] = [];

	if (nodeEditDialog.value.isAdd) {
		nds = [...nodes.value];
	} else {
		nds = nodes.value.filter((node) => node.id !== nodeEditDialog.value.form.nodeId);
	}

	return nds;
});

// 打开添加节点弹框
const openAddNodeDialog = (contextNode: SimulationNodeType) => {
	nodeEditDialog.value.visible = true;
	nodeEditDialog.value.isAdd = true;
	nodeEditDialog.value.form = {
		nodeId: currentNodeId.value,
		nodeName: '',
		nodeType: '',
		relations: []
	};
	currentEditNode.value = contextNode;
};

// 打开编辑节点弹框 - 性能优化版本
const openEditNodeDialog = (node: SimulationNodeType) => {
	const startTime = performance.now();

	const relationInfo = getNodeRelations(node.id);

	const getRelationsTime = performance.now();

	nodeEditDialog.value.visible = true;
	nodeEditDialog.value.isAdd = false;
	nodeEditDialog.value.form = {
		nodeId: node.id,
		nodeName: node.label,
		nodeType: node.type || '',
		relations: relationInfo
			? relationInfo.relationships.map((rel) => ({
					sourceNodeId: rel.link.source,
					targetNodeId: rel.link.target,
					label: rel.link.label || '',
					isHierarchy: rel.link.isHierarchy // 直接使用已优化计算的值
			  }))
			: []
	};
	currentEditNode.value = node;

	const totalTime = performance.now();

	// 性能日志（仅在开发环境下显示）
	if (process.env.NODE_ENV === 'development') {
		const relationCount = relationInfo ? relationInfo.relationships.length : 0;
		console.log(`节点编辑对话框性能统计:`);
		console.log(`  - 获取关系耗时: ${(getRelationsTime - startTime).toFixed(2)}ms`);
		console.log(`  - 数据处理耗时: ${(totalTime - getRelationsTime).toFixed(2)}ms`);
		console.log(`  - 总耗时: ${(totalTime - startTime).toFixed(2)}ms`);
		console.log(`  - 关系数量: ${relationCount}`);
	}
};

// 抽屉关闭处理
const handleDrawerClose = () => {
	nodeEditDialog.value.visible = false;
	resetDialogForm();
};

// 弹框确认处理
const handleDrawerConfirm = () => {
	if (validateForm()) {
		if (nodeEditDialog.value.isAdd) {
			handleAddNodeConfirm();
		} else {
			handleEditNodeConfirm();
		}
	}
};

// 处理添加节点确认
const handleAddNodeConfirm = () => {
	const form = nodeEditDialog.value.form;

	// 生成新的节点ID
	const newNodeId = `node_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;

	// 构造新节点数据
	const newNode = {
		id: newNodeId,
		label: form.nodeName.trim(),
		type: form.nodeType
	};

	// 构造关系数据 - 只包含有效的关系，并处理新节点的引用
	const relationList: LinkItemType[] = form.relations
		.filter((relation) => relation.sourceNodeId && relation.targetNodeId)
		.map((relation) => ({
			source: relation.sourceNodeId === '__NEW_NODE__' ? newNodeId : relation.sourceNodeId,
			target: relation.targetNodeId === '__NEW_NODE__' ? newNodeId : relation.targetNodeId,
			label: relation.label || '',
			isHierarchy:
				relation.isHierarchy || relationTypeMap.value?.get(relation.label)?.isHierarchy || false
		}));

	try {
		// 调用组件的addNode方法
		const result = addNode(newNode, relationList);

		if (result) {
			ElMessage.success('节点添加成功');
			nodeEditDialog.value.visible = false;
			resetDialogForm();

			// 发送事件通知
			emit('node-added', {
				node: result,
				relationList: relationList
			});
		} else {
			ElMessage.error('节点添加失败');
		}
	} catch (error) {
		console.error('添加节点时发生错误:', error);
		ElMessage.error(
			'添加节点时发生错误: ' + (error instanceof Error ? error.message : String(error))
		);
	}
};

// 处理编辑节点确认
const handleEditNodeConfirm = () => {
	const form = nodeEditDialog.value.form;

	// 构造节点更新数据
	const nodeUpdates: NodeUpdateType = {
		label: form.nodeName.trim(),
		type: form.nodeType
	};

	// 构造关系更新数据
	const updatedRelationList: LinkItemType[] = form.relations
		.filter((relation) => relation.sourceNodeId && relation.targetNodeId)
		.map((relation) => ({
			source: relation.sourceNodeId,
			target: relation.targetNodeId,
			label: relation.label || '',
			isHierarchy:
				relation.isHierarchy || relationTypeMap.value?.get(relation.label)?.isHierarchy || false
		}));

	try {
		// 调用组件的editNode方法
		const result = editNode(form.nodeId as string, nodeUpdates, updatedRelationList);

		if (result) {
			ElMessage.success('节点编辑成功');
			nodeEditDialog.value.visible = false;
			resetDialogForm();

			// 发送事件通知
			emit('node-edited', {
				nodeId: form.nodeId as string,
				node: nodeUpdates,
				relationList: updatedRelationList
			});
		} else {
			ElMessage.error('节点编辑失败');
		}
	} catch (error) {
		console.error('编辑节点时发生错误:', error);
		ElMessage.error(
			'编辑节点时发生错误: ' + (error instanceof Error ? error.message : String(error))
		);
	}
};

// 表单验证
const validateForm = () => {
	const form = nodeEditDialog.value.form;

	// 验证节点名称
	if (!form.nodeName || form.nodeName.trim() === '') {
		ElMessage.error('请输入节点名称');
		return false;
	}

	// 验证节点名称长度
	if (form.nodeName.trim().length > 50) {
		ElMessage.error('节点名称长度不能超过50个字符');
		return false;
	}

	// 验证节点类型
	if (!form.nodeType || form.nodeType.trim() === '') {
		ElMessage.error('请选择节点类型');
		return false;
	}

	// 验证节点类型是否存在
	if (!nodeTypeMap.value.has(form.nodeType)) {
		ElMessage.error('选择的节点类型无效，请重新选择');
		return false;
	}

	// 在添加模式下，检查节点名称是否已存在
	if (nodeEditDialog.value.isAdd) {
		const existingNode = nodes.value.find(
			(node) => node.label.trim().toLowerCase() === form.nodeName.trim().toLowerCase()
		);
		if (existingNode) {
			ElMessage.error(`节点名称"${form.nodeName.trim()}"已存在，请使用不同的名称`);
			return false;
		}
	} else {
		// 在编辑模式下，检查节点名称是否与其他节点冲突
		const existingNode = nodes.value.find(
			(node) =>
				node.id !== form.nodeId &&
				node.label.trim().toLowerCase() === form.nodeName.trim().toLowerCase()
		);
		if (existingNode) {
			ElMessage.error(`节点名称"${form.nodeName.trim()}"已被其他节点使用，请使用不同的名称`);
			return false;
		}
	}

	// 验证关系
	const relationPairs = new Set(); // 用于检查重复关系
	for (let i = 0; i < form.relations.length; i++) {
		const relation = form.relations[i];

		// 检查源节点和目标节点是否都已选择
		if (!relation.sourceNodeId || !relation.targetNodeId) {
			ElMessage.error(`请完善第 ${i + 1} 个关系的源节点和目标节点`);
			return false;
		}

		// 检查源节点和目标节点是否相同
		if (relation.sourceNodeId === relation.targetNodeId) {
			ElMessage.error(`第 ${i + 1} 个关系的源节点和目标节点不能相同`);
			return false;
		}

		// 检查节点是否存在 - 使用nodeMap优化
		const sourceNode = getNodeById(relation.sourceNodeId);
		const targetNode = getNodeById(relation.targetNodeId);

		if (!sourceNode && relation.sourceNodeId !== form.nodeId) {
			ElMessage.error(`第 ${i + 1} 个关系的源节点不存在`);
			return false;
		}
		if (!targetNode && relation.targetNodeId !== form.nodeId) {
			ElMessage.error(`第 ${i + 1} 个关系的目标节点不存在`);
			return false;
		}

		// 检查关系类型
		if (relation.label && !relationTypeMap.value.has(relation.label)) {
			ElMessage.error(`第 ${i + 1} 个关系的关系类型无效，请重新选择`);
			return false;
		}

		// 检查重复关系
		const relationKey = `${relation.sourceNodeId}->${relation.targetNodeId}`;
		if (relationPairs.has(relationKey)) {
			ElMessage.error(`第 ${i + 1} 个关系与其他关系重复，同一对节点间只能有一个关系`);
			return false;
		}
		// 获取关系的isHierarchy属性
		const relationType = relationTypeMap.value?.get(relation.label);
		if (relationType) {
			relation.isHierarchy = relationType.isHierarchy || false;
		}
		relationPairs.add(relationKey);
	}

	return true;
};

// 重置弹框表单
const resetDialogForm = () => {
	nodeEditDialog.value.form = {
		nodeId: null,
		nodeName: '',
		nodeType: '',
		relations: []
	};
	currentEditNode.value = null;
};

// 添加关系
const addRelation = () => {
	let newRelation: AddRelationItemType = {
		sourceNodeId: currentNodeId.value || '', // 默认将当前节点作为源节点
		targetNodeId: '',
		label: '',
		isHierarchy: false
	};

	// 将新关系添加到数组的最后面，经过reverse()后显示在列表顶部
	nodeEditDialog.value.form.relations.push(newRelation);
};

// 删除关系
const removeRelation = (index: number) => {
	if (index >= 0 && index < nodeEditDialog.value.form.relations.length) {
		nodeEditDialog.value.form.relations.splice(index, 1);
	}
};

// 检查当前操作的节点是否在指定位置（源或目标）
const isCurrentNodeInPosition = (relation: AddRelationItemType, position: 'source' | 'target') => {
	const currentId = currentNodeId.value;
	if (position === 'source') {
		return relation.sourceNodeId === currentId;
	} else if (position === 'target') {
		return relation.targetNodeId === currentId;
	}
	return false;
};

// 交换关系的源节点和目标节点
const switchRelationDirection = (index: number) => {
	if (index >= 0 && index < nodeEditDialog.value.form.relations.length) {
		const relation = nodeEditDialog.value.form.relations[index];
		const temp = relation.sourceNodeId;
		relation.sourceNodeId = relation.targetNodeId;
		relation.targetNodeId = temp;
	}
};

/** -------------------编辑关系相关------------------- */
// 关系编辑抽屉
const relationEditDialog = ref({
	visible: false,
	form: {
		sourceNodeId: '',
		targetNodeId: '',
		relationLabel: '',
		originalSourceId: '', // 用于记录原始关系，便于更新
		originalTargetId: ''
	}
});
const currentEditRelation = ref<SimulationLinkType | null>(null);
const sourceNodeName = computed(() => {
	const sourceId = relationEditDialog.value.form.sourceNodeId;
	const sourceNode = getNodeById(sourceId);
	return sourceNode ? sourceNode.label : '未知节点';
});
const sourceNodeType = computed(() => {
	const targetId = relationEditDialog.value.form.targetNodeId;
	const targetNode = getNodeById(targetId);
	if (!targetNode) return '未知类型';
	const nodeType = nodeTypeMap.value?.get(targetNode.type);
	return nodeType ? nodeType.type || nodeType.name : targetNode.type || '未知类型';
});
const targetNodeName = computed(() => {
	const targetId = relationEditDialog.value.form.targetNodeId;
	const targetNode = nodes.value.find((n) => n.id === targetId);
	return targetNode ? targetNode.label : '未知节点';
});
const targetNodeType = computed(() => {
	const sourceId = relationEditDialog.value.form.sourceNodeId;
	const sourceNode = getNodeById(sourceId);
	if (!sourceNode) return '未知类型';
	const nodeType = nodeTypeMap.value?.get(sourceNode.type);
	return nodeType ? nodeType.type || nodeType.name : sourceNode.type || '未知类型';
});

// 交换源节点和目标节点
const switchRelationNodes = () => {
	const form = relationEditDialog.value.form;
	const temp = form.sourceNodeId;
	form.sourceNodeId = form.targetNodeId;
	form.targetNodeId = temp;
};

// 打开关系编辑抽屉
const openEditRelationDialog = (link: SimulationLinkType) => {
	const sourceId = link.source.id || link.source;
	const targetId = link.target.id || link.target;

	relationEditDialog.value.visible = true;
	relationEditDialog.value.form = {
		sourceNodeId: sourceId,
		targetNodeId: targetId,
		relationLabel: link.label || '',
		originalSourceId: sourceId,
		originalTargetId: targetId
	};
	currentEditRelation.value = link;
};

// 关系抽屉关闭处理
const handleRelationDrawerClose = () => {
	relationEditDialog.value.visible = false;
	resetRelationDialogForm();
};

// 关系抽屉确认处理
const handleRelationDrawerConfirm = () => {
	if (validateRelationForm()) {
		handleEditRelationConfirm();
	}
};

// 关系表单验证
const validateRelationForm = () => {
	const form = relationEditDialog.value.form;

	// 验证源节点和目标节点
	if (!form.sourceNodeId || !form.targetNodeId) {
		ElMessage.error('请确保源节点和目标节点都已选择');
		return false;
	}

	// 检查源节点和目标节点是否相同
	if (form.sourceNodeId === form.targetNodeId) {
		ElMessage.error('源节点和目标节点不能相同');
		return false;
	}

	// 检查节点是否存在 - 使用nodeMap优化
	const sourceNode = getNodeById(form.sourceNodeId);
	const targetNode = getNodeById(form.targetNodeId);

	if (!sourceNode) {
		ElMessage.error('源节点不存在');
		return false;
	}
	if (!targetNode) {
		ElMessage.error('目标节点不存在');
		return false;
	}

	// 验证关系类型
	if (form.relationLabel && !relationTypeMap.value.has(form.relationLabel)) {
		ElMessage.error('选择的关系类型无效');
		return false;
	}

	// 如果节点关系发生了变化，检查新关系是否已存在
	const sourceChanged = form.sourceNodeId !== form.originalSourceId;
	const targetChanged = form.targetNodeId !== form.originalTargetId;

	if (sourceChanged || targetChanged) {
		const existingLink = links.value.find((link) => {
			const linkSourceId = (link.source as unknown as SimulationNodeType).id || link.source;
			const linkTargetId = (link.target as unknown as SimulationNodeType).id || link.target;
			return linkSourceId === form.sourceNodeId && linkTargetId === form.targetNodeId;
		});

		if (existingLink) {
			ElMessage.error('该关系已存在');
			return false;
		}
	}

	return true;
};

// 处理关系编辑确认
const handleEditRelationConfirm = () => {
	const form = relationEditDialog.value.form;

	try {
		// 如果源节点和目标节点发生了变化，需要删除原关系，新增新关系
		const sourceChanged = form.sourceNodeId !== form.originalSourceId;
		const targetChanged = form.targetNodeId !== form.originalTargetId;

		if (sourceChanged || targetChanged) {
			// 删除原关系
			removeRelationNew(form.originalSourceId, form.originalTargetId);

			// 添加新关系
			const result = addRelationNew({
				source: form.sourceNodeId,
				target: form.targetNodeId,
				label: form.relationLabel,
				isHierarchy: relationTypeMap.value?.get(form.relationLabel)?.isHierarchy || false
			});

			if (result) {
				ElMessage.success('关系更新成功');
				relationEditDialog.value.visible = false;
				resetRelationDialogForm();

				// 发送事件通知
				emit('relation-edited', {
					oldRelation: {
						source: form.originalSourceId,
						target: form.originalTargetId,
						label: form.relationLabel
					},
					newRelation: result
				});
			} else {
				ElMessage.error('关系更新失败');
			}
		} else {
			// 只更新关系属性
			const result = updateRelationNew({
				source: form.sourceNodeId,
				target: form.targetNodeId,
				label: form.relationLabel,
				isHierarchy: relationTypeMap.value?.get(form.relationLabel)?.isHierarchy || false
			});

			if (result) {
				ElMessage.success('关系更新成功');
				relationEditDialog.value.visible = false;
				resetRelationDialogForm();

				// 发送事件通知
				emit('relation-edited', {
					relation: {
						source: form.sourceNodeId,
						target: form.targetNodeId,
						label: form.relationLabel
					}
				});
			} else {
				ElMessage.error('关系更新失败');
			}
		}
	} catch (error) {
		console.error('编辑关系时发生错误:', error);
		ElMessage.error('编辑关系时发生错误: ' + (error instanceof Error ? error.message : '未知错误'));
	}
};

// 删除节点关系
const removeRelationNew = (source: string, target: string) => {
	// 验证输入参数
	if (!source || !target) {
		ElMessage.error('删除关系必须提供 source 和 target 节点ID');
		return false;
	}

	// 查找对应的关系
	const linkIndex = links.value.findIndex((link) => {
		const linkSourceId = (link.source as unknown as SimulationNodeType).id || link.source;
		const linkTargetId = (link.target as unknown as SimulationNodeType).id || link.target;
		return linkSourceId === source && linkTargetId === target;
	});

	if (linkIndex === -1) {
		ElMessage.error(`未找到从节点 ${source} 到节点 ${target} 的关系`);
		return false;
	}

	// 获取要删除的关系信息（用于日志）
	const deletedLink = { ...links.value[linkIndex] };

	// 从连接列表中删除
	links.value.splice(linkIndex, 1);

	// 重新预处理数据和缓存
	preprocessLinkData();

	// 更新模拟和渲染
	updateSimulation();
	renderGraph();

	console.log(`成功删除关系: ${source} → ${target}`, deletedLink);
	return true;
};

// 批量删除节点关系（支持删除多个关系）预留
/* eslint-disable @typescript-eslint/no-unused-vars */
const removeRelations = (relationPairs: { source: string; target: string }[]) => {
	// 验证输入参数
	if (!Array.isArray(relationPairs) || relationPairs.length === 0) {
		ElMessage.error('批量删除关系需要提供关系对数组');
		return false;
	}

	let deletedCount = 0;
	const deletedRelations: LinkItemType[] = [];

	relationPairs.forEach(({ source, target }) => {
		if (!source || !target) {
			console.warn(`跳过无效的关系对: source=${source}, target=${target}`);
			return;
		}

		// 查找对应的关系
		const linkIndex = links.value.findIndex((link) => {
			const linkSourceId = (link.source as unknown as SimulationNodeType).id || link.source;
			const linkTargetId = (link.target as unknown as SimulationNodeType).id || link.target;
			return linkSourceId === source && linkTargetId === target;
		});

		if (linkIndex !== -1) {
			const deletedLink = { ...links.value[linkIndex] };
			links.value.splice(linkIndex, 1);
			deletedRelations.push(deletedLink);
			deletedCount++;
		} else {
			console.warn(`未找到从节点 ${source} 到节点 ${target} 的关系`);
		}
	});

	if (deletedCount > 0) {
		// 重新预处理数据和缓存
		preprocessLinkData();

		// 更新模拟和渲染
		updateSimulation();
		renderGraph();

		console.log(`成功批量删除 ${deletedCount} 个关系`, deletedRelations);
	}

	return {
		success: deletedCount > 0,
		deletedCount: deletedCount,
		deletedRelations: deletedRelations
	};
};

// 新增节点关系（支持单个和批量添加）
const addRelationNew = (
	relationData: LinkItemType | LinkItemType[]
): AddRelationResultType | LinkItemType | boolean | null => {
	// 验证输入参数
	if (!relationData) {
		ElMessage.error('新增关系需要提供关系数据');
		return false;
	}

	// 判断是单个关系还是关系数组
	const relations = Array.isArray(relationData) ? relationData : [relationData];

	if (relations.length === 0) {
		ElMessage.error('关系数组不能为空');
		return false;
	}

	const results: AddRelationResultType = {
		added: [],
		failed: [],
		skipped: [], // 已存在的关系
		updated: [],
		total: relations.length
	};

	relations.forEach((relation, index) => {
		try {
			// 验证单个关系数据
			if (!relation || typeof relation !== 'object') {
				results.failed.push({
					index,
					relation,
					error: '关系数据必须是对象格式'
				});
				return;
			}

			const { source, target, ...linkAttributes } = relation;

			// 必须提供源节点和目标节点ID
			if (!source || !target) {
				results.failed.push({
					index,
					relation,
					error: '新增关系必须提供 source 和 target 节点ID'
				});
				return;
			}

			// 检查源节点和目标节点是否存在 - 使用nodeMap优化
			const sourceNode = getNodeById(source);
			const targetNode = getNodeById(target);

			if (!sourceNode) {
				results.failed.push({
					index,
					relation,
					error: `源节点 ${source} 不存在`
				});
				return;
			}

			if (!targetNode) {
				results.failed.push({
					index,
					relation,
					error: `目标节点 ${target} 不存在`
				});
				return;
			}

			// 检查关系是否已存在
			const existingLink = links.value.find((link) => {
				const linkSourceId = (link.source as unknown as SimulationNodeType).id || link.source;
				const linkTargetId = (link.target as unknown as SimulationNodeType).id || link.target;
				return linkSourceId === source && linkTargetId === target;
			});

			if (existingLink) {
				results.skipped.push({
					index,
					relation,
					existingRelation: existingLink,
					reason: `从节点 ${source} 到节点 ${target} 的关系已存在`
				});
				return;
			}

			// 创建新的关系对象
			const newLink = {
				...linkAttributes,
				source: source,
				target: target,
				label: linkAttributes.label || '',
				isHierarchy:
					linkAttributes.isHierarchy ||
					relationTypeMap.value?.get(linkAttributes.label)?.isHierarchy ||
					false
			};

			// 添加到连接列表
			links.value.push(newLink);

			results.added.push({
				index,
				relation: newLink
			});

			console.log(`成功新增关系: ${source} → ${target}`, newLink);
		} catch (error) {
			results.failed.push({
				index,
				relation,
				error: error instanceof Error ? error.message : '处理关系时发生未知错误'
			});
		}
	});

	// 只有在有成功添加时才更新图形
	if (results.added.length > 0) {
		// 重新预处理数据和缓存
		preprocessLinkData();

		// 更新模拟和渲染
		updateSimulation();
		renderGraph();
	}

	// 输出操作汇总
	if (results.added.length > 0) {
		console.log(`批量添加完成: 新增了 ${results.added.length} 个关系`);
	}
	if (results.skipped.length > 0) {
		console.log(`批量添加中跳过了 ${results.skipped.length} 个已存在的关系`);
	}
	if (results.failed.length > 0) {
		console.warn(`批量添加中有 ${results.failed.length} 个关系处理失败:`, results.failed);
	}

	// 如果是单个关系，返回简化的结果
	if (!Array.isArray(relationData)) {
		if (results.failed.length > 0) {
			// 单个操作失败，显示错误消息
			const error = results.failed[0];
			ElMessage.error(error.error);
			return false;
		}
		if (results.skipped.length > 0) {
			// 单个操作被跳过（关系已存在）
			const skipped = results.skipped[0];
			ElMessage.warning(skipped.reason);
			return null; // 返回 null 表示关系已存在，未添加
		}
		if (results.added.length > 0) {
			// 单个操作成功
			return results.added[0].relation;
		}
		return false;
	}

	// 批量操作返回详细结果
	return {
		success: results.added.length > 0,
		...results
	};
};

// 更新节点关系（支持单个关系和批量关系）
const updateRelationNew = (
	relationData: LinkItemType | LinkItemType[]
): AddRelationResultType | boolean | string => {
	// 验证输入参数
	if (!relationData) {
		ElMessage.error('更新关系需要提供关系数据');
		return false;
	}

	// 判断是单个关系还是关系数组
	const relations = Array.isArray(relationData) ? relationData : [relationData];

	if (relations.length === 0) {
		ElMessage.error('关系数组不能为空');
		return false;
	}

	const results: AddRelationResultType = {
		updated: [],
		skipped: [],
		added: [],
		failed: [],
		total: relations.length
	};

	relations.forEach((relationUpdate, index) => {
		try {
			// 验证单个关系数据
			if (!relationUpdate || typeof relationUpdate !== 'object') {
				results.failed.push({
					index,
					relation: relationUpdate,
					error: '关系数据必须是对象格式'
				});
				return;
			}

			const { source, target, ...updates } = relationUpdate;

			// 必须提供源节点和目标节点ID
			if (!source || !target) {
				results.failed.push({
					index,
					relation: relationUpdate,
					error: '必须提供 source 和 target 节点ID'
				});
				return;
			}

			// 检查源节点和目标节点是否存在 - 使用nodeMap优化
			const sourceNode = getNodeById(source);
			const targetNode = getNodeById(target);

			if (!sourceNode) {
				results.failed.push({
					index,
					relation: relationUpdate,
					error: `源节点 ${source} 不存在`
				});
				return;
			}

			if (!targetNode) {
				results.failed.push({
					index,
					relation: relationUpdate,
					error: `目标节点 ${target} 不存在`
				});
				return;
			}

			// 查找对应的关系
			const linkIndex = links.value.findIndex((link) => {
				const linkSourceId = (link.source as unknown as SimulationNodeType).id || link.source;
				const linkTargetId = (link.target as unknown as SimulationNodeType).id || link.target;
				return linkSourceId === source && linkTargetId === target;
			});

			if (linkIndex !== -1) {
				// 关系存在，进行更新
				const originalLink = { ...links.value[linkIndex] };
				Object.assign(links.value[linkIndex], updates);

				// 确保 source 和 target 不被意外修改
				links.value[linkIndex].source = originalLink.source;
				links.value[linkIndex].target = originalLink.target;

				results.updated.push({
					index,
					relation: { source, target, ...updates },
					originalData: originalLink
				});

				console.log(`成功更新关系: ${source} → ${target}`, updates);
			} else {
				// 关系不存在，进行添加（复用 addRelation 的逻辑）
				const newLink = {
					...updates,
					source: source,
					target: target,
					label: updates.label || '',
					isHierarchy:
						updates.isHierarchy || relationTypeMap.value?.get(updates.label)?.isHierarchy || false
				};

				links.value.push(newLink);

				results.added.push({
					index,
					relation: newLink
				});

				console.log(`成功新增关系: ${source} → ${target}`, newLink);
			}
		} catch (error) {
			results.failed.push({
				index,
				relation: relationUpdate,
				error: error instanceof Error ? error.message : '处理关系时发生未知错误'
			});
		}
	});

	// 只有在有成功操作时才更新图形
	if (results.updated.length > 0 || results.added.length > 0) {
		// 重新预处理数据和缓存
		preprocessLinkData();

		// 更新模拟和渲染
		updateSimulation();
		renderGraph();
	}

	// 输出操作汇总
	if (results.updated.length > 0) {
		console.log(`批量更新完成: 更新了 ${results.updated.length} 个关系`);
	}
	if (results.added.length > 0) {
		console.log(`批量添加完成: 新增了 ${results.added.length} 个关系`);
	}
	if (results.failed.length > 0) {
		console.warn(`批量操作中有 ${results.failed.length} 个关系处理失败:`, results.failed);
	}

	// 如果是单个关系，返回简化的结果
	if (!Array.isArray(relationData)) {
		if (results.failed.length > 0) {
			return false;
		}
		return results.updated.length > 0 ? 'updated' : 'added';
	}

	// 批量操作返回详细结果
	return {
		success: results.updated.length > 0 || results.added.length > 0,
		...results
	};
};

// 重置关系弹框表单
const resetRelationDialogForm = () => {
	relationEditDialog.value.form = {
		sourceNodeId: '',
		targetNodeId: '',
		relationLabel: '',
		originalSourceId: '',
		originalTargetId: ''
	};
	currentEditRelation.value = null;
};

/** -------------------公共API方法------------------- */
// API1: 高亮指定节点（可传入多个节点ID）
const highlightNodes = (nodeIds: string | string[] = []) => {
	// 清除之前的高亮
	clearHighlight();
	if (typeof nodeIds === 'string') {
		nodeIds = [nodeIds];
	}
	if (!Array.isArray(nodeIds) || nodeIds.length === 0) {
		return;
	}

	const nodeIdSet = new Set<string>(nodeIds);

	// 展开相关的收起节点
	expandRelatedNodes(nodeIdSet);

	// 获取高亮的节点
	const highlightedNodes = nodes.value.filter((node) => nodeIdSet.has(node.id));

	// 高亮指定的节点
	zoomGroup.value
		?.selectAll('.node-group')
		.classed('highlighted', (d) => nodeIdSet.has((d as SimulationNodeType).id))
		.classed('dimmed', (d) => !nodeIdSet.has((d as SimulationNodeType).id));

	// 高亮指定节点的标签组
	zoomGroup.value
		?.selectAll('.node-label-group')
		.classed('highlighted', (d) => nodeIdSet.has((d as SimulationNodeType).id))
		.classed('dimmed', (d) => !nodeIdSet.has((d as SimulationNodeType).id));

	// 连接线和连接标签保持默认状态（不高亮）
	zoomGroup.value?.selectAll('.link, .link-label').classed('dimmed', true);

	// 将高亮节点移动到画布中央
	if (highlightedNodes.length > 0) {
		centerToNodes(highlightedNodes, true);
	}
};

// API2: 高亮指定节点及其直接相关节点和连线 - 优化版本
const highlightNodesWithRelations = (nodeIds: string | string[] = []) => {
	// 清除之前的高亮
	clearHighlight();
	if (typeof nodeIds === 'string') {
		nodeIds = [nodeIds];
	}
	if (!Array.isArray(nodeIds) || nodeIds.length === 0) {
		return;
	}

	const inputNodeIds = new Set(nodeIds);
	const connectedNodeIds = new Set(nodeIds);

	// 使用预计算的邻居表，避免遍历所有连线
	nodeIds.forEach((nodeId) => {
		const neighbors = nodeNeighbors.value?.get(nodeId);
		if (neighbors) {
			neighbors.forEach((neighborId) => connectedNodeIds.add(neighborId));
		}
	});

	// 展开相关的收起节点（包括直接相关节点）
	expandRelatedNodes(connectedNodeIds);

	// 高亮节点（包括指定节点和相关节点）
	zoomGroup.value
		?.selectAll('.node-group')
		.classed('highlighted', (d) => connectedNodeIds.has((d as SimulationNodeType).id))
		.classed('dimmed', (d) => !connectedNodeIds.has((d as SimulationNodeType).id));

	// 高亮相关连接线
	zoomGroup.value
		?.selectAll('.link')
		.classed('highlighted', (d) => {
			const sourceId = (d as SimulationLinkType).source.id || (d as SimulationLinkType).source;
			const targetId = (d as SimulationLinkType).target.id || (d as SimulationLinkType).target;
			return inputNodeIds.has(sourceId) || inputNodeIds.has(targetId);
		})
		.classed('dimmed', (d) => {
			const sourceId = (d as SimulationLinkType).source.id || (d as SimulationLinkType).source;
			const targetId = (d as SimulationLinkType).target.id || (d as SimulationLinkType).target;
			return !(inputNodeIds.has(sourceId) || inputNodeIds.has(targetId));
		})
		.attr('marker-end', (d) => {
			const sourceId = (d as SimulationLinkType).source.id || (d as SimulationLinkType).source;
			const targetId = (d as SimulationLinkType).target.id || (d as SimulationLinkType).target;
			const isConnected = inputNodeIds.has(sourceId) || inputNodeIds.has(targetId);
			if ((d as SimulationLinkType).isHierarchy === true) {
				return isConnected ? 'url(#arrowhead-highlight)' : 'url(#arrowhead)';
			} else {
				return 'none';
			}
		});

	// 高亮相关连接标签
	zoomGroup.value
		?.selectAll('.link-label')
		.classed('highlighted', (d) => {
			const sourceId = (d as SimulationLinkType).source.id || (d as SimulationLinkType).source;
			const targetId = (d as SimulationLinkType).target.id || (d as SimulationLinkType).target;
			return inputNodeIds.has(sourceId) || inputNodeIds.has(targetId);
		})
		.classed('dimmed', (d) => {
			const sourceId = (d as SimulationLinkType).source.id || (d as SimulationLinkType).source;
			const targetId = (d as SimulationLinkType).target.id || (d as SimulationLinkType).target;
			return !(inputNodeIds.has(sourceId) || inputNodeIds.has(targetId));
		});

	// 高亮节点标签组
	zoomGroup.value
		?.selectAll('.node-label-group')
		.classed('highlighted', (d) => connectedNodeIds.has((d as SimulationNodeType).id))
		.classed('dimmed', (d) => !connectedNodeIds.has((d as SimulationNodeType).id));

	// 将相关节点移动到画布中央
	const relatedNodes = nodes.value.filter((node) => connectedNodeIds.has(node.id));
	if (relatedNodes.length > 0) {
		centerToNodes(relatedNodes, true);
	}
};

// API3: 高亮指定关系类型的节点和连线（根据links的label）
const highlightRelationsByLabel = (relationLabels: string | string[] = []) => {
	// 清除之前的高亮
	clearHighlight();
	// 如果relationLabels是字符串，转换为数组
	if (typeof relationLabels === 'string') {
		relationLabels = [relationLabels];
	}
	if (!Array.isArray(relationLabels) || relationLabels.length === 0) {
		return;
	}

	const relationLabelSet = new Set(relationLabels);
	const connectedNodeIds = new Set<string>();

	// 找到匹配指定关系标签的连接
	const matchingLinks = links.value.filter((link) => {
		return link.label && relationLabelSet.has(link.label);
	});

	// 收集所有相关节点ID
	matchingLinks.forEach((link) => {
		const sourceId = (link as SimulationLinkType).source.id || (link as SimulationLinkType).source;
		const targetId = (link as SimulationLinkType).target.id || (link as SimulationLinkType).target;
		connectedNodeIds.add(sourceId);
		connectedNodeIds.add(targetId);
	});

	if (connectedNodeIds.size === 0) {
		console.warn(`未找到标签为 [${relationLabels.join(', ')}] 的关系`);
		return;
	}

	// 展开相关的收起节点
	expandRelatedNodes(connectedNodeIds);

	// 高亮相关节点
	zoomGroup.value
		?.selectAll('.node-group')
		.classed('highlighted', (d) => connectedNodeIds.has((d as SimulationNodeType).id))
		.classed('dimmed', (d) => !connectedNodeIds.has((d as SimulationNodeType).id));

	// 高亮匹配的连接线
	zoomGroup.value
		?.selectAll('.link')
		.classed('highlighted', (d) => {
			return Boolean(
				(d as SimulationLinkType).label && relationLabelSet.has((d as SimulationLinkType).label)
			);
		})
		.classed('dimmed', (d) => {
			return (
				!(d as SimulationLinkType).label && relationLabelSet.has((d as SimulationLinkType).label)
			);
		})
		.attr('marker-end', (d) => {
			const isMatching =
				(d as SimulationLinkType).label && relationLabelSet.has((d as SimulationLinkType).label);
			if ((d as SimulationLinkType).isHierarchy === true) {
				return isMatching ? 'url(#arrowhead-highlight)' : 'url(#arrowhead)';
			} else {
				return 'none';
			}
		});

	// 高亮匹配的连接标签
	zoomGroup.value
		?.selectAll('.link-label')
		.classed('highlighted', (d) => {
			return Boolean(
				(d as SimulationLinkType).label && relationLabelSet.has((d as SimulationLinkType).label)
			);
		})
		.classed('dimmed', (d) => {
			return (
				!(d as SimulationLinkType).label && relationLabelSet.has((d as SimulationLinkType).label)
			);
		});

	// 高亮相关节点标签
	zoomGroup.value
		?.selectAll('.node-label')
		.classed('highlighted', (d) => connectedNodeIds.has((d as SimulationNodeType).id))
		.classed('dimmed', (d) => !connectedNodeIds.has((d as SimulationNodeType).id));

	// 将相关节点移动到画布中央
	const relationNodes = nodes.value.filter((node) => connectedNodeIds.has(node.id));
	if (relationNodes.length > 0) {
		centerToNodes(relationNodes, true);
	}
};

// API4: 按节点类型高亮指定节点（可传入多个类型）
const highlightNodesByType = (nodeTypes: string | string[] = []) => {
	// 清除之前的高亮
	clearHighlight();
	if (typeof nodeTypes === 'string') {
		nodeTypes = [nodeTypes];
	}
	if (!Array.isArray(nodeTypes) || nodeTypes.length === 0) {
		return;
	}

	const nodeTypeSet = new Set(nodeTypes);

	// 获取匹配类型的节点
	const matchingNodes = nodes.value.filter((node) => node.type && nodeTypeSet.has(node.type));

	if (matchingNodes.length === 0) {
		console.warn(`未找到类型为 [${nodeTypes.join(', ')}] 的节点`);
		return;
	}

	// 展开相关的收起节点
	const matchingNodeIds = new Set<string>(matchingNodes.map((node) => node.id));
	expandRelatedNodes(matchingNodeIds);

	// 高亮匹配类型的节点
	zoomGroup.value
		?.selectAll('.node-group')
		.classed(
			'highlighted',
			(d) =>
				Boolean((d as SimulationNodeType).type) && nodeTypeSet.has((d as SimulationNodeType).type)
		)
		.classed(
			'dimmed',
			(d) => !(d as SimulationNodeType).type && nodeTypeSet.has((d as SimulationNodeType).type)
		);

	// 高亮匹配类型节点的标签组
	zoomGroup.value
		?.selectAll('.node-label-group')
		.classed(
			'highlighted',
			(d) =>
				Boolean((d as SimulationNodeType).type) && nodeTypeSet.has((d as SimulationNodeType).type)
		)
		.classed(
			'dimmed',
			(d) => !(d as SimulationNodeType).type && nodeTypeSet.has((d as SimulationNodeType).type)
		);

	// 连接线和连接标签保持默认状态（不高亮）
	zoomGroup.value?.selectAll('.link, .link-label').classed('dimmed', true);

	// 将匹配类型的节点移动到画布中央
	if (matchingNodes.length > 0) {
		centerToNodes(matchingNodes, true);
	}
};

// API5: 按节点类型高亮节点及其关系网络 - 优化版本
const highlightNodesByTypeWithRelations = (nodeTypes: string | string[] = []) => {
	// 清除之前的高亮
	clearHighlight();
	if (typeof nodeTypes === 'string') {
		nodeTypes = [nodeTypes];
	}
	if (!Array.isArray(nodeTypes) || nodeTypes.length === 0) {
		return;
	}

	const nodeTypeSet = new Set(nodeTypes);

	// 找到匹配类型的节点ID
	const matchingNodeIds = new Set<string>();
	nodes.value.forEach((node) => {
		if (node.type && nodeTypeSet.has(node.type)) {
			matchingNodeIds.add(node.id);
		}
	});

	if (matchingNodeIds.size === 0) {
		console.warn(`未找到类型为 [${nodeTypes.join(', ')}] 的节点`);
		return;
	}

	// 使用预计算的邻居表，避免遍历所有连线
	const connectedNodeIds = new Set(matchingNodeIds);
	matchingNodeIds.forEach((nodeId) => {
		const neighbors = nodeNeighbors.value?.get(nodeId);
		if (neighbors) {
			neighbors.forEach((neighborId) => connectedNodeIds.add(neighborId));
		}
	});

	// 展开相关的收起节点（包括相关节点）
	expandRelatedNodes(connectedNodeIds);

	// 高亮节点（包括指定类型节点和相关节点）
	zoomGroup.value
		?.selectAll('.node-group')
		.classed('highlighted', (d) => connectedNodeIds.has((d as SimulationNodeType).id))
		.classed('dimmed', (d) => !connectedNodeIds.has((d as SimulationNodeType).id));

	// 高亮相关连接线
	zoomGroup.value
		?.selectAll('.link')
		.classed('highlighted', (d) => {
			const sourceId = (d as SimulationLinkType).source.id || (d as SimulationLinkType).source;
			const targetId = (d as SimulationLinkType).target.id || (d as SimulationLinkType).target;
			return matchingNodeIds.has(sourceId) || matchingNodeIds.has(targetId);
		})
		.classed('dimmed', (d) => {
			const sourceId = (d as SimulationLinkType).source.id || (d as SimulationLinkType).source;
			const targetId = (d as SimulationLinkType).target.id || (d as SimulationLinkType).target;
			return !(matchingNodeIds.has(sourceId) || matchingNodeIds.has(targetId));
		})
		.attr('marker-end', (d) => {
			const sourceId = (d as SimulationLinkType).source.id || (d as SimulationLinkType).source;
			const targetId = (d as SimulationLinkType).target.id || (d as SimulationLinkType).target;
			const isConnected = matchingNodeIds.has(sourceId) || matchingNodeIds.has(targetId);
			if ((d as SimulationLinkType).isHierarchy === true) {
				return isConnected ? 'url(#arrowhead-highlight)' : 'url(#arrowhead)';
			} else {
				return 'none';
			}
		});

	// 高亮相关连接标签
	zoomGroup.value
		?.selectAll('.link-label')
		.classed('highlighted', (d) => {
			const sourceId = (d as SimulationLinkType).source.id || (d as SimulationLinkType).source;
			const targetId = (d as SimulationLinkType).target.id || (d as SimulationLinkType).target;
			return matchingNodeIds.has(sourceId) || matchingNodeIds.has(targetId);
		})
		.classed('dimmed', (d) => {
			const sourceId = (d as SimulationLinkType).source.id || (d as SimulationLinkType).source;
			const targetId = (d as SimulationLinkType).target.id || (d as SimulationLinkType).target;
			return !(matchingNodeIds.has(sourceId) || matchingNodeIds.has(targetId));
		});

	// 高亮节点标签组
	zoomGroup.value
		?.selectAll('.node-label-group')
		.classed('highlighted', (d) => connectedNodeIds.has((d as SimulationNodeType).id))
		.classed('dimmed', (d) => !connectedNodeIds.has((d as SimulationNodeType).id));

	// 将相关节点移动到画布中央
	const relatedNodes = nodes.value.filter((node) => connectedNodeIds.has(node.id));
	if (relatedNodes.length > 0) {
		centerToNodes(relatedNodes, true);
	}
};

// API6: 按照节点标签（label）高亮节点
const highlightNodesByLabel = (nodeLabels: string | string[] = []) => {
	// 清除之前的高亮
	clearHighlight();

	// 如果nodeLabels是字符串，转换为数组
	if (typeof nodeLabels === 'string') {
		nodeLabels = [nodeLabels];
	}

	if (!Array.isArray(nodeLabels) || nodeLabels.length === 0) {
		return;
	}

	// 支持模糊匹配
	const matchingNodes = nodes.value.filter((node) => {
		if (!node.label) return false;
		// 检查节点标签是否包含任意一个搜索词
		return (
			!props.excludeNodeList.includes(String(node.id)) &&
			nodeLabels.some((searchLabel) => node.label.toLowerCase().includes(searchLabel.toLowerCase()))
		);
	});

	if (matchingNodes.length === 0) {
		console.warn(`未找到标签包含 [${nodeLabels.join(', ')}] 的节点`);
		return;
	}

	const matchingNodeIds = new Set<string>(matchingNodes.map((node) => node.id));

	// 展开相关的收起节点
	expandRelatedNodes(matchingNodeIds);

	// 高亮匹配的节点
	zoomGroup.value
		?.selectAll('.node-group')
		.classed('highlighted', (d) => matchingNodeIds.has((d as SimulationNodeType).id))
		.classed('dimmed', (d) => !matchingNodeIds.has((d as SimulationNodeType).id));

	// 高亮匹配节点的标签组
	zoomGroup.value
		?.selectAll('.node-label-group')
		.classed('highlighted', (d) => matchingNodeIds.has((d as SimulationNodeType).id))
		.classed('dimmed', (d) => !matchingNodeIds.has((d as SimulationNodeType).id));

	// 连接线和连接标签保持默认状态（不高亮）
	zoomGroup.value?.selectAll('.link, .link-label').classed('dimmed', true);

	// 将匹配的节点移动到画布中央
	if (matchingNodes.length > 0) {
		centerToNodes(matchingNodes, true);
	}
};

// API7: 按照节点标签（label）高亮节点及其关系
const highlightNodesByLabelWithRelations = (nodeLabels: string | string[] = []) => {
	// 清除之前的高亮
	clearHighlight();

	// 如果nodeLabels是字符串，转换为数组
	if (typeof nodeLabels === 'string') {
		nodeLabels = [nodeLabels];
	}

	if (!Array.isArray(nodeLabels) || nodeLabels.length === 0) {
		return;
	}

	// 支持模糊匹配
	const matchingNodes = nodes.value.filter((node) => {
		if (!node.label) return false;
		// 检查节点标签是否包含任意一个搜索词
		return (
			!props.excludeNodeList.includes(String(node.id)) &&
			nodeLabels.some((searchLabel) => node.label.toLowerCase().includes(searchLabel.toLowerCase()))
		);
	});

	if (matchingNodes.length === 0) {
		console.warn(`未找到标签包含 [${nodeLabels.join(', ')}] 的节点`);
		return;
	}

	const matchingNodeIds = new Set<string>(matchingNodes.map((node) => node.id));
	const connectedNodeIds = new Set<string>(matchingNodeIds);

	// 使用预计算的邻居表，找出所有相关节点
	matchingNodeIds.forEach((nodeId) => {
		const neighbors = nodeNeighbors.value?.get(nodeId);
		if (neighbors) {
			neighbors.forEach((neighborId) => connectedNodeIds.add(neighborId));
		}
	});

	// 展开相关的收起节点（包括相关节点）
	expandRelatedNodes(connectedNodeIds);

	// 高亮节点（包括匹配节点和相关节点）
	zoomGroup.value
		?.selectAll('.node-group')
		.classed('highlighted', (d) => connectedNodeIds.has((d as SimulationNodeType).id))
		.classed('dimmed', (d) => !connectedNodeIds.has((d as SimulationNodeType).id));

	// 高亮相关连接线
	zoomGroup.value
		?.selectAll('.link')
		.classed('highlighted', (d) => {
			const sourceId = (d as SimulationLinkType).source.id || (d as SimulationLinkType).source;
			const targetId = (d as SimulationLinkType).target.id || (d as SimulationLinkType).target;
			return matchingNodeIds.has(sourceId) || matchingNodeIds.has(targetId);
		})
		.classed('dimmed', (d) => {
			const sourceId = (d as SimulationLinkType).source.id || (d as SimulationLinkType).source;
			const targetId = (d as SimulationLinkType).target.id || (d as SimulationLinkType).target;
			return !(matchingNodeIds.has(sourceId) || matchingNodeIds.has(targetId));
		})
		.attr('marker-end', (d) => {
			const sourceId = (d as SimulationLinkType).source.id || (d as SimulationLinkType).source;
			const targetId = (d as SimulationLinkType).target.id || (d as SimulationLinkType).target;
			const isConnected = matchingNodeIds.has(sourceId) || matchingNodeIds.has(targetId);
			if ((d as SimulationLinkType).isHierarchy === true) {
				return isConnected ? 'url(#arrowhead-highlight)' : 'url(#arrowhead)';
			} else {
				return 'none';
			}
		});

	// 高亮相关连接标签
	zoomGroup.value
		?.selectAll('.link-label')
		.classed('highlighted', (d) => {
			const sourceId = (d as SimulationLinkType).source.id || (d as SimulationLinkType).source;
			const targetId = (d as SimulationLinkType).target.id || (d as SimulationLinkType).target;
			return matchingNodeIds.has(sourceId) || matchingNodeIds.has(targetId);
		})
		.classed('dimmed', (d) => {
			const sourceId = (d as SimulationLinkType).source.id || (d as SimulationLinkType).source;
			const targetId = (d as SimulationLinkType).target.id || (d as SimulationLinkType).target;
			return !(matchingNodeIds.has(sourceId) || matchingNodeIds.has(targetId));
		});

	// 高亮节点标签组
	zoomGroup.value
		?.selectAll('.node-label-group')
		.classed('highlighted', (d) => connectedNodeIds.has((d as SimulationNodeType).id))
		.classed('dimmed', (d) => !connectedNodeIds.has((d as SimulationNodeType).id));

	// 将相关节点移动到画布中央
	const relatedNodes = nodes.value.filter((node) => connectedNodeIds.has(node.id));
	if (relatedNodes.length > 0) {
		centerToNodes(relatedNodes, true);
	}
};

// API8: 清除所有高亮状态
const clearAllHighlight = () => {
	clearHighlight();
};

// API9: 定位到中心
const fitToCenter = () => {
	if (!nodes.value || nodes.value.length === 0) return;

	// 获取隐藏的节点ID集合，排除收起的节点
	const hiddenNodeIds = getHiddenNodeIds();
	// 过滤隐藏的节点
	const filteredNodes = nodes.value.filter((node) => !hiddenNodeIds.has(node.id));

	// 使用 centerToNodes 方法居中显示所有节点，使用默认中心位置
	centerToNodes(filteredNodes as SimulationNodeType[], true);
};

// API10: 放大（增加缩放值）
const zoomIn = () => {
	const step = 10; // 每次增加 10%
	const newValue = Math.min(400, internalZoomValue.value + step);
	internalZoomValue.value = newValue;
	applyZoomFromValue(newValue);
};

// API11: 缩小（减少缩放值）
const zoomOut = () => {
	const step = 10; // 每次减少 10%
	const newValue = Math.max(20, internalZoomValue.value - step);
	internalZoomValue.value = newValue;
	applyZoomFromValue(newValue);
};

// API12: 设置缩放值
const setZoomValue = (value: number) => {
	const clampedValue = Math.max(20, Math.min(400, value));
	internalZoomValue.value = clampedValue;
	applyZoomFromValue(clampedValue);
};

// API13: 获取当前缩放值
const getZoomValue = () => {
	return internalZoomValue.value;
};

// API14: 按层级展示节点
const showByLevel = (level: string | number) => {
	if (!nodeChildrenMap.value || nodeChildrenMap.value.size === 0) {
		console.warn('节点关系信息未初始化，无法按层级展示');
		return;
	}

	try {
		if (level === 'all') {
			// 全部展开：所有有子节点的节点都设置为展开状态
			nodeChildrenMap.value.forEach((_, nodeId) => {
				nodeExpandState.value.set(nodeId, true);
			});
		} else {
			// 数字表示展开到第几层（level 从 0 开始，根节点是第 0 层）
			const targetLevel = parseInt(String(level));
			if (isNaN(targetLevel)) {
				console.warn('无效的层级参数:', level);
				return;
			}

			// 遍历所有有子节点的节点，根据层级设置展开状态
			nodeChildrenMap.value.forEach((_, nodeId) => {
				const nodeLevel = nodeLevelMap.value.get(nodeId) || 0;
				// 如果当前层级小于目标层级，则展开；否则收起
				const shouldExpand = nodeLevel < targetLevel;
				if (shouldExpand) {
					nodeExpandState.value.set(nodeId, shouldExpand);
				}
			});
		}

		// 更新节点和连接的可见性
		updateNodeVisibility();

		// 重新渲染展开/收起按钮
		const nodesGroup = zoomGroup.value?.select('.nodes-group');
		if (nodesGroup) {
			const nodeUpdate = nodesGroup.selectAll('.node-group') as d3.Selection<
				SVGGElement,
				SimulationNodeType,
				SVGGElement,
				unknown
			>;
			renderExpandCollapseButtons(nodeUpdate);
		}

		// 等待 DOM 更新和布局稳定后居中显示
		nextTick(() => {
			setTimeout(() => {
				fitToCenter();
			}, 100); // 延迟一点确保 force simulation 布局稳定
		});
	} catch (error) {
		console.error('按层级展示时出错:', error);
	}
};

/** -------------------工具方法------------------- */
// 文本换行处理
const wrapText = (text: string, maxWidth: number, fontSize: number): string[] => {
	// 创建临时的 SVG text 元素来测量文本宽度
	const tempText = zoomGroup.value
		?.append('text')
		.attr('font-size', fontSize)
		.style('visibility', 'hidden');

	if (!tempText) return [text];

	const lines = [];
	let currentLine = '';

	// 逐字符处理
	for (let i = 0; i < text.length; i++) {
		const char = text[i];
		const testLine = currentLine + char;

		tempText.text(testLine);
		const width = tempText.node()?.getComputedTextLength() || 0;

		if (width > maxWidth && currentLine.length > 0) {
			// 当前行已满，保存并开始新行
			lines.push(currentLine);
			currentLine = char;
		} else {
			currentLine = testLine;
		}
	}

	// 添加最后一行
	if (currentLine.length > 0) {
		lines.push(currentLine);
	}

	// 删除临时元素
	tempText.remove();

	return lines.length > 0 ? lines : [text];
};

// 获取节点（替换 find 操作）
const getNodeById = (nodeId: string) => {
	return nodeMap.value?.get(nodeId) || null;
};

// 从 nodeMap 中删除节点
const removeNodeFromMap = (nodeId: string) => {
	nodeMap.value?.delete(nodeId);
};

// 获取节点所有直接相关的关系 - 高性能优化版本
const getNodeRelations = (nodeId: string) => {
	// 验证节点是否存在 - 使用nodeMap优化
	const targetNode = getNodeById(nodeId);
	if (!targetNode) {
		console.warn(`节点 ${nodeId} 不存在`);
		return null;
	}

	// 使用预处理的有效连线，提高性能
	const relatedLinks = validLinks.value.filter((link) => {
		const sourceId = (link.source as unknown as SimulationNodeType).id || link.source;
		const targetId = (link.target as unknown as SimulationNodeType).id || link.target;
		return sourceId === nodeId || targetId === nodeId;
	});

	// 使用邻居缓存获取相关节点ID
	const relatedNodeIds = nodeNeighbors.value?.get(nodeId) || new Set();

	// 预构建节点ID到节点对象的映射，避免重复查找
	const nodeMap = new Map();
	relatedNodeIds.forEach((id) => {
		const node = nodes.value.find((n) => n.id === id);
		if (node) nodeMap.set(id, node);
	});
	nodeMap.set(nodeId, targetNode); // 添加目标节点自身

	// 获取相关节点的完整信息
	const relatedNodes = Array.from(nodeMap.values()).filter((node) => node.id !== nodeId);

	// 构建关系信息，包含方向性 - 性能优化版本
	const relationships = relatedLinks.map((link) => {
		const sourceId = (link.source as unknown as SimulationNodeType).id || link.source;
		const targetId = (link.target as unknown as SimulationNodeType).id || link.target;

		// 使用预构建的映射避免重复查找
		const sourceNode = nodeMap?.get(sourceId);
		const targetNodeInLink = nodeMap?.get(targetId);

		// 预计算isHierarchy，避免重复Map查找
		const relationType = relationTypeMap.value?.get(link.label);
		const isHierarchy = link.isHierarchy || relationType?.isHierarchy || false;

		return {
			// 连接信息
			link: {
				source: sourceId,
				target: targetId,
				label: link.label || '',
				isHierarchy: isHierarchy
			},
			// 关系方向（相对于查询节点）
			direction: sourceId === nodeId ? 'outgoing' : 'incoming',
			// 对方节点信息
			relatedNode: sourceId === nodeId ? targetNodeInLink : sourceNode,
			// 延迟计算关系描述（仅在需要时计算）
			get relationDescription() {
				return sourceId === nodeId
					? `${targetNode.label} → ${targetNodeInLink?.label || '未知节点'}`
					: `${sourceNode?.label || '未知节点'} → ${targetNode.label}`;
			}
		};
	});

	return {
		// 目标节点信息
		targetNode: targetNode,
		// 相关节点列表
		relatedNodes: relatedNodes,
		// 相关连接列表
		relatedLinks: relatedLinks,
		// 详细关系信息（包含方向）
		relationships: relationships,
		// 统计信息
		statistics: {
			totalRelations: relatedLinks.length,
			incomingRelations: relationships.filter((r) => r.direction === 'incoming').length,
			outgoingRelations: relationships.filter((r) => r.direction === 'outgoing').length,
			hierarchyRelations: relatedLinks.filter((l) => l.isHierarchy === true).length,
			cooperationRelations: relatedLinks.filter((l) => l.isHierarchy === false).length
		}
	};
};

// 将多个节点的中心移动到画布中央
const centerToNodes = (nodes: SimulationNodeType[], useDefaultCenter = false) => {
	if (!nodes || nodes.length === 0) return;

	// 计算所有节点的中心点
	let centerX = 0,
		centerY = 0;
	nodes.forEach((node) => {
		centerX += node.x || 0;
		centerY += node.y || 0;
	});
	centerX /= nodes.length;
	centerY /= nodes.length;

	// 计算所有节点的边界框
	let minX = Infinity,
		maxX = -Infinity,
		minY = Infinity,
		maxY = -Infinity;
	nodes.forEach((node) => {
		const radius = (node.size || props.defaultNodeStyle.size) / 2;
		minX = Math.min(minX, (node.x || 0) - radius);
		maxX = Math.max(maxX, (node.x || 0) + radius);
		minY = Math.min(minY, (node.y || 0) - radius);
		maxY = Math.max(maxY, (node.y || 0) + radius);
	});

	const boundsWidth = maxX - minX;
	const boundsHeight = maxY - minY;

	// 计算合适的缩放比例，确保所有节点都在视图中
	const padding = 50; // 边距
	const scaleX = (width.value - padding * 2) / boundsWidth;
	const scaleY = (height.value - padding * 2) / boundsHeight;
	let targetScale = Math.min(scaleX, scaleY);

	// 限制缩放范围
	const currentTransform = d3.zoomTransform(svg.value?.node() as SVGSVGElement);
	targetScale = Math.min(Math.max(targetScale, 0.2), 4); // 与zoom的scaleExtent一致

	// 如果只有单个节点或节点很集中，保持当前缩放
	if (boundsWidth < 100 && boundsHeight < 100) {
		// targetScale = currentTransform.k;
		targetScale = currentTransform.k < 1.5 ? 1.5 : currentTransform.k;
	}

	// 计算平移参数，根据是否使用默认中心位置来决定目标位置
	const targetX = useDefaultCenter ? width.value / 2 : width.value * props.centerPosition[0];
	const targetY = useDefaultCenter ? height.value / 2 : height.value * props.centerPosition[1];
	// 新坐标 = 原坐标 * 缩放比例 + 偏移量
	// centerX = (targetX - x) / scale
	// targetX = centerX * scale + x
	const x = -centerX * targetScale + targetX;
	const y = -centerY * targetScale + targetY;

	// 应用动画变换
	if (zoom.value && svg.value) {
		const transform = d3.zoomIdentity.translate(x, y).scale(targetScale);
		const transition = svg.value.transition().duration(750) as d3.Transition<
			SVGSVGElement,
			unknown,
			null,
			undefined
		>;
		zoom.value.transform(transition, transform);
	}
};

// 添加节点 - 添加缓存更新
const addNode = (node: SimulationNodeType, relationList: LinkItemType[]) => {
	// 验证节点数据
	if (!node.id || !node.label) {
		ElMessage.error('节点必须有 id and label 属性');
		return;
	}

	// 检查ID是否已存在 - 使用nodeMap优化
	if (getNodeById(node.id)) {
		ElMessage.error('节点 id 已经存在了', node.id);
		return;
	}
	// 创建新节点
	const nodeTypeConfig = nodeTypeMap.value?.get(node.type);
	const newNode = {
		...node,
		color: node.color || nodeTypeConfig?.color || props.defaultNodeStyle?.color,
		size: node.size || nodeTypeConfig?.size || props.defaultNodeStyle?.size,
		backgroundImg:
			resolveImagePath(node.backgroundImg || nodeTypeConfig?.backgroundImg || '') || '',
		// 渐变配置
		gradientStops: node.gradientStops || nodeTypeConfig?.gradientStops,
		gradientType: node.gradientType || nodeTypeConfig?.gradientType || 'linear', // 'linear' 或 'radial'
		gradientDir: node.gradientDir || nodeTypeConfig?.gradientDir || [0, 0, 0, 1],
		x: Math.random() * width.value,
		y: Math.random() * height.value,
		vx: 0,
		vy: 0,
		// 图片加载状态
		_imageLoaded: false,
		_imageLoadFailed: false
	};

	// 添加节点
	nodes.value.push(newNode);
	// 更新nodeMap缓存
	updateNodeInMap(newNode);

	// 添加连接（支持字符串或对象格式）
	relationList.forEach((relation) => {
		let sourceId: string, targetId: string, linkData: LinkItemType;

		if (typeof relation === 'string') {
			// 兼容原有格式：简单的目标节点ID字符串
			sourceId = relation;
			linkData = {
				source: sourceId,
				target: node.id,
				// 默认连接属性
				label: '',
				isHierarchy: false
			};
		} else if (typeof relation === 'object' && (relation.source || relation.target)) {
			// 新格式：完整的连接对象
			sourceId = relation.source || node.id;
			targetId = relation.target || node.id;

			linkData = {
				// 支持其他自定义属性
				...relation,
				source: sourceId,
				target: targetId,
				label: relation.label || '',
				isHierarchy:
					relation.isHierarchy || relationTypeMap.value?.get(relation.label)?.isHierarchy || false
			};
		} else {
			console.warn('无效的连接格式:', relation);
			return;
		}

		// 验证连接数据的完整性
		if (!linkData.source || !linkData.target) {
			ElMessage.error('连接数据无效:', linkData);
			return;
		}

		// 检查目标节点是否存在 - 使用nodeMap优化
		const sourceNode = getNodeById(sourceId);
		if (sourceNode) {
			links.value.push(linkData);
		} else {
			console.warn(`目标节点不存在: ${sourceId}`);
		}
	});

	// 重新预处理数据和缓存
	preprocessLinkData();

	// 更新图形
	updateSimulation();
	renderGraph();

	return newNode;
};

// 编辑节点（可能包含节点关系）- 全量操作模式
const editNode = (nodeId: string, updates: NodeUpdateType, updatedRelationList: LinkItemType[]) => {
	const nodeIndex = nodes.value.findIndex((n) => n.id === nodeId);
	// 也可以优化为： const targetNode = this._getNodeById(nodeId); if (!targetNode) return false;
	if (nodeIndex === -1) {
		ElMessage.error('节点没有找到');
		return false;
	}

	// 更新节点数据（排除连接相关的更新）
	if (Object.keys(updates).length > 0) {
		Object.assign(nodes.value[nodeIndex], updates);
	}

	// 全量更新连接关系（如果提供了updatedRelationList参数）
	if (updatedRelationList && Array.isArray(updatedRelationList)) {
		// 1. 找到所有与该节点相关的现有连接
		const currentRelatedLinks = links.value.filter((link) => {
			const sourceId = (link.source as unknown as SimulationNodeType).id || link.source;
			const targetId = (link.target as unknown as SimulationNodeType).id || link.target;
			return sourceId === nodeId || targetId === nodeId;
		});

		// 2. 创建传入连接的标识集合，用于快速查找
		const incomingRelationListSet = new Set();
		const validUpdatedRelationList: ValidUpdatedRelationItemType[] = [];

		updatedRelationList.forEach((connUpdate, index) => {
			const { target, source, ...linkUpdates } = connUpdate;

			// 确定实际的源节点和目标节点ID
			let actualSourceId: string, actualTargetId: string;

			if (target && source) {
				// 指定了源和目标
				actualSourceId = source;
				actualTargetId = target;
			} else if (target) {
				// 只指定了目标，当前节点作为源
				actualSourceId = nodeId;
				actualTargetId = target;
			} else if (source) {
				// 只指定了源，当前节点作为目标
				actualSourceId = source;
				actualTargetId = nodeId;
			} else {
				console.warn(`跳过无效的连接更新（索引${index}）:`, connUpdate);
				return;
			}

			// 验证节点存在性
			const sourceExists = nodes.value.find((n) => n.id === actualSourceId);
			const targetExists = nodes.value.find((n) => n.id === actualTargetId);

			if (!sourceExists || !targetExists) {
				console.warn(
					`跳过连接更新（索引${index}）- 节点不存在: source=${actualSourceId}, target=${actualTargetId}`
				);
				return;
			}

			// 创建连接标识
			const relationKey = `${actualSourceId}->${actualTargetId}`;
			incomingRelationListSet.add(relationKey);

			validUpdatedRelationList.push({
				sourceId: actualSourceId,
				targetId: actualTargetId,
				updates: linkUpdates,
				relationKey: relationKey
			});
		});

		// 3. 删除现有关系中不在传入关系列表中的连接
		const linksToRemove = currentRelatedLinks.filter((link) => {
			const sourceId = (link.source as unknown as SimulationNodeType).id || link.source;
			const targetId = (link.target as unknown as SimulationNodeType).id || link.target;
			const relationKey = `${sourceId}->${targetId}`;
			return !incomingRelationListSet.has(relationKey);
		});

		linksToRemove.forEach((linkToRemove) => {
			const linkIndex = links.value.findIndex((l) => l === linkToRemove);
			if (linkIndex !== -1) {
				const sourceId =
					(linkToRemove.source as unknown as SimulationNodeType).id || linkToRemove.source;
				const targetId =
					(linkToRemove.target as unknown as SimulationNodeType).id || linkToRemove.target;
				links.value.splice(linkIndex, 1);
				console.log(`删除关系: ${sourceId} → ${targetId}`);
			}
		});

		// 4. 新增或更新传入的连接关系
		validUpdatedRelationList.forEach(({ sourceId, targetId, updates }) => {
			// 查找现有连接
			const existingLinkIndex = links.value.findIndex((link) => {
				const linkSourceId = (link.source as unknown as SimulationNodeType).id || link.source;
				const linkTargetId = (link.target as unknown as SimulationNodeType).id || link.target;
				return linkSourceId === sourceId && linkTargetId === targetId;
			});

			if (existingLinkIndex !== -1) {
				// 更新现有连接
				const originalLink = { ...links.value[existingLinkIndex] };
				Object.assign(links.value[existingLinkIndex], updates);

				// 确保 source 和 target 不被意外修改
				links.value[existingLinkIndex].source = originalLink.source;
				links.value[existingLinkIndex].target = originalLink.target;

				console.log(`更新关系: ${sourceId} → ${targetId}`, updates);
			} else {
				// 新增连接
				const newLink = {
					...updates,
					source: sourceId,
					target: targetId,
					label: updates.label || '',
					isHierarchy:
						updates.isHierarchy || relationTypeMap.value?.get(updates.label)?.isHierarchy || false
				};

				links.value.push(newLink);
				console.log(`新增关系: ${sourceId} → ${targetId}`, newLink);
			}
		});

		// 5. 重新预处理数据和缓存
		preprocessLinkData();

		// 6. 更新模拟
		updateSimulation();
	}

	// 重新渲染
	renderGraph();

	return true;
};

// 移除节点 - 添加缓存更新
const removeNodeById = (nodeId: string) => {
	// 移除节点
	nodes.value = nodes.value.filter((n) => n.id !== nodeId);
	// 从 nodeMap 中删除
	removeNodeFromMap(nodeId);

	// 移除相关连接
	links.value = links.value.filter(
		(l) =>
			(l.source as unknown as SimulationNodeType).id ||
			(l.source !== nodeId && (l.target as unknown as SimulationNodeType).id) ||
			l.target !== nodeId
	);

	// 清除焦点状态
	if (focusedNode.value?.id === nodeId) {
		unfocus();
	}

	// 重新预处理数据和缓存
	preprocessLinkData();

	// 更新图形
	updateSimulation();
	renderGraph();

	return true;
};

// 更新nodeMap中的单个节点
const updateNodeInMap = (node: SimulationNodeType) => {
	if (node && node.id) {
		nodeMap.value.set(node.id, node);
	}
};

defineExpose({
	highlightNodes,
	highlightNodesWithRelations,
	highlightRelationsByLabel,
	highlightNodesByType,
	highlightNodesByTypeWithRelations,
	highlightNodesByLabel,
	highlightNodesByLabelWithRelations,
	clearAllHighlight,
	fitToCenter,
	showByLevel,
	zoomIn,
	zoomOut,
	setZoomValue,
	getZoomValue
});
</script>

<style scoped lang="scss">
.network-graph-container {
	position: relative;
	width: 100%;
	height: 100%;
	overflow: hidden;
	-webkit-user-select: none; /* Safari */
	-ms-user-select: none; /* IE 10+ 和 Edge */
	user-select: none; /* 标准语法 */
}

.network-svg {
	width: 100%;
	height: 100%;
	cursor: grab;
	display: block;
}
.network-svg:active {
	cursor: grabbing;
}

/* 连接线样式 */
:deep(.link) {
	opacity: 1;
	stroke: #ccc;
	stroke-width: 1px;
	transition: all 0.3s ease;
}
:deep(.link.highlighted) {
	stroke: #4a90e2;
}
:deep(.link.dimmed) {
	opacity: 0.3;
}
:deep(.link.hover-highlighted) {
	stroke: #4a90e2;
}
:deep(.link.hover-dimmed) {
	opacity: 0.3;
}

/* 连接标签样式 */
:deep(.link-label) {
	font-family: 'Alibaba PuHuiTi', 'Arial', sans-serif;
	-webkit-user-select: none; /* Safari */
	-ms-user-select: none; /* IE 10+ 和 Edge */
	user-select: none; /* 标准语法 */
	fill: #333;
	text-anchor: middle;
	dominant-baseline: central;
	font-size: 10px;
	font-weight: 700;
	pointer-events: none;
	text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.8);
	transition: all 0.3s ease;
}
:deep(.link-label.highlighted) {
	fill: #4a90e2;
}
:deep(.link-label.dimmed) {
	opacity: 0.3;
}
:deep(.link-label.hover-highlighted) {
	fill: #4a90e2;
}
:deep(.link-label.hover-dimmed) {
	opacity: 0.3;
}

/* 编辑模式下的连线标签 */
:deep(.link-label.editable) {
	pointer-events: all;
	cursor: pointer;
}
:deep(.link-label.editable:hover) {
	fill: #409eff;
	font-weight: 800;
}

/* 节点标签组样式 */
:deep(.node-label-group) {
	pointer-events: none;
	transition: all 0.3s ease;
}

:deep(.node-label-group.highlighted) {
	opacity: 1;
}

:deep(.node-label-group.dimmed) {
	opacity: 0.3;
}

:deep(.node-label-group.hover-highlighted) {
	opacity: 1;
}

:deep(.node-label-group.hover-dimmed) {
	opacity: 0.3;
}

/* 节点标签样式 */
:deep(.node-label) {
	font-family: 'Alibaba PuHuiTi', 'Arial', sans-serif;
	-webkit-user-select: none; /* Safari */
	-ms-user-select: none; /* IE 10+ 和 Edge */
	user-select: none; /* 标准语法 */
	fill: #999;
	text-anchor: middle;
	dominant-baseline: central;
	font-size: 10px;
	font-weight: 400;
	pointer-events: none;
	transition: all 0.3s ease;
}

/* 底部标签样式 */
:deep(.node-label-bottom) {
	fill: #999;
	font-weight: 400;
}

/* 中心标签样式 */
:deep(.node-label-center) {
	fill: #fff;
	font-weight: 500;
	font-size: 10px;
}

:deep(.node-label-group.highlighted .node-label) {
	fill: #666;
}

:deep(.node-label-group.hover-highlighted .node-label) {
	fill: #666;
}
:deep(.node-label-group.highlighted .node-label.node-label-center) {
	fill: #fff;
}

:deep(.node-label-group.hover-highlighted .node-label.node-label-center) {
	fill: #fff;
}

/* 编辑模式下的节点标签 */
:deep(.node-label.editable) {
	pointer-events: all;
	cursor: pointer;
}

:deep(.node-label.editable:hover) {
	fill: #409eff;
	font-weight: 500;
}

/* 多行标签的悬停效果 - 当整个 labelGroup 悬停时，所有文本行都高亮 */
:deep(.multi-line-label:hover .node-label.editable) {
	fill: #409eff;
	font-weight: 500;
}

/* 节点样式 */
:deep(.node-group) {
	cursor: pointer;
	transition: all 0.3s ease;
}

/* 展开/收起按钮样式 */
:deep(.expand-collapse-button) {
	transition: opacity 0.2s ease;
}

:deep(.expand-collapse-circle) {
	transition: all 0.2s ease;
}

:deep(.expand-collapse-circle:hover) {
	fill: #f0f0f0;
	stroke: #4a90e2;
	stroke-width: 1.5;
}

:deep(.expand-collapse-icon) {
	pointer-events: none;
}
:deep(.node-circle) {
	transition: all 0.3s ease;
}
/* 只对有背景图的节点应用 paint-order，避免 stroke 遮挡背景图 */
:deep(.node-circle.has-background-img) {
	paint-order: stroke fill; /* 先绘制 stroke，再绘制 fill */
}
:deep(.node-group.highlighted .node-circle) {
	stroke: #fff;
	stroke-width: 3px;
	filter: drop-shadow(0 0 6px rgba(255, 255, 255, 1));
}
:deep(.node-group.dimmed) {
	opacity: 0.3;
}
:deep(.node-group.hover-highlighted .node-circle) {
	stroke: #fff;
	stroke-width: 3px;
	filter: drop-shadow(0 0 6px rgba(255, 255, 255, 1));
}
:deep(.node-group.hover-dimmed) {
	opacity: 0.3;
}

/* 右键菜单样式 */
.context-menu {
	position: absolute;
	background: rgba(255, 255, 255, 0.95);
	backdrop-filter: blur(10px);
	border-radius: 12px;
	box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
	padding: 8px 0;
	min-width: 180px;
	z-index: 1000;
	border: 1px solid rgba(255, 255, 255, 0.3);
	animation: contextMenuFadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
@keyframes contextMenuFadeIn {
	from {
		opacity: 0;
		transform: scale(0.9) translateY(-10px);
	}

	to {
		opacity: 1;
		transform: scale(1) translateY(0);
	}
}

.menu-item {
	display: flex;
	align-items: center;
	padding: 12px 16px;
	cursor: pointer;
	transition: all 0.15s ease;
	font-size: 14px;
	color: #333;
	gap: 12px;
	.icon-add::before {
		content: '➕';
	}
	.icon-edit::before {
		content: '✏️';
	}
	.icon-delete::before {
		content: '🗑️';
	}
}

.menu-item:hover {
	background: rgba(52, 152, 219, 0.1);
	color: #3498db;
}
.menu-item.danger {
	color: #e74c3c;
}
.menu-item.danger:hover {
	background: rgba(231, 76, 60, 0.1);
	color: #c0392b;
}
.menu-separator {
	height: 1px;
	background: rgba(0, 0, 0, 0.1);
	margin: 4px 12px;
}

/* 节点信息气泡框样式 */
.node-tooltip {
	position: fixed;
	background: #ffffff;
	border: 1px solid #e2e8f0;
	border-radius: 8px;
	box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
	z-index: 999;
	min-width: 180px;
	max-width: 280px;
	padding: 12px 16px;
	font-family: 'Alibaba PuHuiTi', 'Arial', sans-serif;
	pointer-events: auto;
	-webkit-user-select: none;
	-ms-user-select: none;
	user-select: none;

	.tooltip-content {
		.tooltip-title {
			font-size: 14px;
			font-weight: 600;
			color: #2d3748;
			margin-bottom: 6px;
			line-height: 1.4;
			word-break: break-word;
		}

		.tooltip-type {
			font-size: 12px;
			color: #718096;
			line-height: 1.4;
		}
	}

	.tooltip-arrow {
		position: absolute;
		width: 0;
		height: 0;
		border: 6px solid transparent;
		border-top-color: #ffffff;
		bottom: -12px;
		left: 50%;
		transform: translateX(-50%);
		filter: drop-shadow(0 2px 2px rgba(0, 0, 0, 0.05));
	}

	// 箭头边框（模拟边框效果）
	&::before {
		content: '';
		position: absolute;
		width: 0;
		height: 0;
		border: 7px solid transparent;
		border-top-color: #e2e8f0;
		bottom: -14px;
		left: 50%;
		transform: translateX(-50%);
		z-index: -1;
	}
}

/* 节点编辑抽屉样式 */
.drawer-content {
	height: 100%;
	display: flex;
	flex-direction: column;

	.drawer-body {
		flex: 1;
		overflow-y: auto;
		padding: 20px;
	}

	.drawer-footer {
		display: flex;
		justify-content: flex-end;
		gap: 12px;
		padding: 16px 20px;
		border-top: 1px solid #e1e8ed;
		background: #f8fafc;
		flex-shrink: 0;
	}

	.form-section {
		margin-bottom: 32px;
		h4 {
			margin: 0 0 16px 0;
			font-size: 16px;
			font-weight: 600;
			color: #2d3748;
		}

		.empty-state {
			text-align: center;
			color: #718096;
			padding: 40px 20px;
			font-size: 14px;
			background: #f7fafc;
			border-radius: 8px;
			border: 2px dashed #e2e8f0;
		}
	}

	.form-section:last-child {
		margin-bottom: 0;
	}
	.section-header {
		display: flex;
		justify-content: space-between;
		align-items: center;
		margin-bottom: 16px;
		h4 {
			margin: 0;
		}
	}

	.btn-add {
		display: flex;
		align-items: center;
		gap: 6px;
		padding: 8px 12px;
		background: #4299e1;
		color: white;
		border: none;
		border-radius: 8px;
		cursor: pointer;
		font-size: 14px;
		font-weight: 500;
		transition: all 0.2s ease;
	}

	.btn-add:hover {
		background: #3182ce;
		transform: translateY(-1px);
	}

	.btn-add .icon-add::before {
		content: '+';
		font-weight: bold;
	}

	.form-row {
		display: flex;
		gap: 16px;
		margin-bottom: 16px;

		.form-group {
			flex: 1;
		}

		.form-group.full-width {
			flex: 1;
		}

		.form-group label {
			display: block;
			margin-bottom: 6px;
			font-size: 14px;
			font-weight: 500;
			color: #4a5568;
		}

		.form-input,
		.form-select {
			width: 100%;
			padding: 10px 12px;
			border: 2px solid #e2e8f0;
			border-radius: 8px;
			font-size: 14px;
			transition: all 0.2s ease;
			background: white;
		}

		.form-input:focus,
		.form-select:focus {
			outline: none;
			border-color: #4299e1;
			box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.1);
		}

		.direction-switch {
			display: flex;
			align-items: end;
			.btn-switch {
				background: #f7fafc;
				border: 2px solid #e2e8f0;
				border-radius: 8px;
				cursor: pointer;
				font-size: 16px;
				color: #4a5568;
				transition: all 0.2s ease;
				min-width: 40px;
				height: 32px;
				display: flex;
				align-items: center;
				justify-content: center;
			}

			.btn-switch:hover {
				background: #edf2f7;
				border-color: #cbd5e0;
				color: #2d3748;
			}
		}
	}
	.form-row:last-child {
		margin-bottom: 0;
	}
	.form-row.direction-row {
		align-items: end;
	}

	.relation-item {
		border: 2px solid #e2e8f0;
		border-radius: 12px;
		margin-bottom: 16px;
		background: #f9fafb;
		overflow: hidden;

		.relation-header {
			display: flex;
			justify-content: space-between;
			align-items: center;
			padding: 12px 16px;
			background: #f1f5f9;
			border-bottom: 1px solid #e2e8f0;
		}

		.relation-index {
			font-size: 14px;
			font-weight: 600;
			color: #4a5568;
		}

		.btn-remove {
			display: flex;
			align-items: center;
			gap: 4px;
			padding: 6px 10px;
			background: #fed7d7;
			color: #c53030;
			border: none;
			border-radius: 6px;
			cursor: pointer;
			font-size: 12px;
			font-weight: 500;
			transition: all 0.2s ease;
		}

		.btn-remove:hover {
			background: #feb2b2;
			color: #9b2c2c;
		}

		.btn-remove .icon-delete::before {
			content: '×';
			font-size: 14px;
			font-weight: bold;
		}

		.relation-form {
			padding: 16px;
		}

		/* 当前节点显示样式 */
		.current-node-display {
			display: flex;
			align-items: center;
			gap: 8px;
			height: 32px;
			padding: 4px 12px;
			background: #edf2f7;
			border: 2px solid #cbd5e0;
			border-radius: 6px;
			font-size: 14px;
		}

		.current-node-text {
			color: #2d3748;
			font-weight: 500;
		}

		.current-node-badge {
			background: #4299e1;
			color: white;
			padding: 2px 8px;
			border-radius: 12px;
			font-size: 12px;
			font-weight: 500;
		}
	}

	.relation-item:last-child {
		margin-bottom: 0;
	}

	/* 关系编辑特定样式 */
	.relation-direction-container {
		background: #f9fafb;
		border: 2px solid #e2e8f0;
		border-radius: 12px;
		padding: 20px;
		margin-top: 10px;

		.direction-row {
			display: flex;
			align-items: center;
			justify-content: space-between;
			gap: 16px;
		}

		.node-info {
			flex: 1;
			text-align: center;

			.node-label {
				font-size: 14px;
				font-weight: 600;
				color: #4a5568;
				margin-bottom: 8px;
			}

			.node-display {
				background: white;
				border: 2px solid #cbd5e0;
				border-radius: 8px;
				padding: 12px;
				box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);

				.node-name {
					display: block;
					font-size: 16px;
					font-weight: 600;
					color: #2d3748;
					margin-bottom: 4px;
				}

				.node-type {
					font-size: 12px;
					color: #718096;
					font-style: italic;
				}
			}
		}

		.source-node .node-display {
			border-color: #4299e1;
			background: linear-gradient(135deg, #e6f3ff 0%, #ffffff 100%);
		}

		.target-node .node-display {
			border-color: #48bb78;
			background: linear-gradient(135deg, #f0fff4 0%, #ffffff 100%);
		}

		.direction-arrow {
			position: relative;
			top: 14px;
			display: flex;
			flex-direction: column;
			align-items: center;
			gap: 8px;
			min-width: 80px;

			.btn-switch-direction {
				background: #4299e1;
				color: white;
				border: none;
				border-radius: 50%;
				width: 40px;
				height: 40px;
				cursor: pointer;
				font-size: 18px;
				display: flex;
				align-items: center;
				justify-content: center;
				transition: all 0.2s ease;
				box-shadow: 0 2px 6px rgba(66, 153, 225, 0.3);
			}

			.btn-switch-direction:hover {
				background: #3182ce;
				transform: translateY(-2px);
				box-shadow: 0 4px 12px rgba(66, 153, 225, 0.4);
			}
		}
	}
}
</style>
